From cc079b6683aa7b597530de247e08b2326941898e Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 26 Dec 2022 10:40:49 +0100 Subject: [PATCH 001/250] Fix %eval sometimes off by one centipawn --- chess/engine.py | 14 +++++++------- chess/pgn.py | 2 +- test.py | 6 ++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index a431df7da..f319d09bf 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1538,16 +1538,16 @@ def _go(self, limit: Limit, *, root_moves: Optional[Iterable[chess.Move]] = None builder.append("ponder") if limit.white_clock is not None: builder.append("wtime") - builder.append(str(max(1, int(limit.white_clock * 1000)))) + builder.append(str(max(1, round(limit.white_clock * 1000)))) if limit.black_clock is not None: builder.append("btime") - builder.append(str(max(1, int(limit.black_clock * 1000)))) + builder.append(str(max(1, round(limit.black_clock * 1000)))) if limit.white_inc is not None: builder.append("winc") - builder.append(str(int(limit.white_inc * 1000))) + builder.append(str(round(limit.white_inc * 1000))) if limit.black_inc is not None: builder.append("binc") - builder.append(str(int(limit.black_inc * 1000))) + builder.append(str(round(limit.black_inc * 1000))) if limit.remaining_moves is not None and int(limit.remaining_moves) > 0: builder.append("movestogo") builder.append(str(int(limit.remaining_moves))) @@ -1562,7 +1562,7 @@ def _go(self, limit: Limit, *, root_moves: Optional[Iterable[chess.Move]] = None builder.append(str(max(1, int(limit.mate)))) if limit.time is not None: builder.append("movetime") - builder.append(str(max(1, int(limit.time * 1000)))) + builder.append(str(max(1, round(limit.time * 1000)))) if infinite: builder.append("infinite") if root_moves is not None: @@ -2160,9 +2160,9 @@ def start(self, engine: XBoardProtocol) -> None: if limit.depth is not None: engine.send_line(f"sd {max(1, int(limit.depth))}") if limit.white_clock is not None: - engine.send_line("{} {}".format("time" if board.turn else "otim", max(1, int(limit.white_clock * 100)))) + engine.send_line("{} {}".format("time" if board.turn else "otim", max(1, round(limit.white_clock * 100)))) if limit.black_clock is not None: - engine.send_line("{} {}".format("otim" if board.turn else "time", max(1, int(limit.black_clock * 100)))) + engine.send_line("{} {}".format("otim" if board.turn else "time", max(1, round(limit.black_clock * 100)))) if draw_offered and engine.features.get("draw", 1): engine.send_line("draw") diff --git a/chess/pgn.py b/chess/pgn.py index da97866c3..f802a780f 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -420,7 +420,7 @@ def eval(self) -> Optional[chess.engine.PovScore]: # who has been mated. return chess.engine.PovScore(score, turn) else: - score = chess.engine.Cp(int(float(match.group("cp")) * 100)) + score = chess.engine.Cp(round(float(match.group("cp")) * 100)) return chess.engine.PovScore(score if turn else -score, turn) diff --git a/test.py b/test.py index b9be057e1..29ea02749 100755 --- a/test.py +++ b/test.py @@ -2806,6 +2806,12 @@ def test_annotations(self): game.set_arrows([]) self.assertEqual(game.comment, "foo [%bar] baz") + def test_eval(self): + game = chess.pgn.Game() + for cp in range(199, 220): + game.set_eval(chess.engine.PovScore(chess.engine.Cp(cp), chess.WHITE)) + self.assertEqual(game.eval().white().cp, cp) + def test_float_emt(self): game = chess.pgn.Game() game.comment = "[%emt 0:00:01.234]" From 8628abbb65386f6622cf38d519209e123a654b8b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 29 Dec 2022 21:50:24 +0100 Subject: [PATCH 002/250] Keep misc PGN headers in insertion order --- chess/pgn.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index f802a780f..1a01b034e 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -810,11 +810,11 @@ def setup(self, board: Union[chess.Board, str]) -> None: fen = setup.fen() if fen == type(setup).starting_fen: - self.headers.pop("SetUp", None) self.headers.pop("FEN", None) + self.headers.pop("SetUp", None) else: - self.headers["SetUp"] = "1" self.headers["FEN"] = fen + self.headers["SetUp"] = "1" if type(setup).aliases[0] == "Standard" and setup.chess960: self.headers["Variant"] = "Chess960" @@ -957,7 +957,7 @@ def __iter__(self) -> Iterator[str]: if key in self._tag_roster: yield key - yield from sorted(self._others) + yield from self._others def __len__(self) -> int: return len(self._tag_roster) + len(self._others) From 6e1f435ba60536a1d36728b9309427777f2c5198 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 5 Jan 2023 20:16:10 +0100 Subject: [PATCH 003/250] Try Sphinx 6.x --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index dd8706637..f18b82961 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -Sphinx==5.3.0 +Sphinx==6.1.1 From b3e634d21e7b0c4262da89a766f1dd1a00a2baa2 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 5 Jan 2023 20:21:27 +0100 Subject: [PATCH 004/250] Fix indent of :raises: lists --- chess/__init__.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 883d5fbda..e205bba8e 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -2987,9 +2987,10 @@ def parse_san(self, san: str) -> Move: :raises: :exc:`ValueError` (specifically an exception specified below) if the SAN is invalid, illegal or ambiguous. - - :exc:`InvalidMoveError` if the SAN is syntactically invalid. - - :exc:`IllegalMoveError` if the SAN is illegal. - - :exc:`AmbiguousMoveError` if the SAN is ambiguous. + + - :exc:`InvalidMoveError` if the SAN is syntactically invalid. + - :exc:`IllegalMoveError` if the SAN is illegal. + - :exc:`AmbiguousMoveError` if the SAN is ambiguous. """ # Castling. try: @@ -3072,9 +3073,10 @@ def push_san(self, san: str) -> Move: :raises: :exc:`ValueError` (specifically an exception specified below) if neither legal nor a null move. - - :exc:`InvalidMoveError` if the SAN is syntactically invalid. - - :exc:`IllegalMoveError` if the SAN is illegal. - - :exc:`AmbiguousMoveError` if the SAN is ambiguous. + + - :exc:`InvalidMoveError` if the SAN is syntactically invalid. + - :exc:`IllegalMoveError` if the SAN is illegal. + - :exc:`AmbiguousMoveError` if the SAN is ambiguous. """ move = self.parse_san(san) self.push(move) @@ -3105,8 +3107,9 @@ def parse_uci(self, uci: str) -> Move: :raises: :exc:`ValueError` (specifically an exception specified below) if the move is invalid or illegal in the current position (but not a null move). - - :exc:`InvalidMoveError` if the UCI is syntactically invalid. - - :exc:`IllegalMoveError` if the UCI is illegal. + + - :exc:`InvalidMoveError` if the UCI is syntactically invalid. + - :exc:`IllegalMoveError` if the UCI is illegal. """ move = Move.from_uci(uci) @@ -3130,8 +3133,9 @@ def push_uci(self, uci: str) -> Move: :raises: :exc:`ValueError` (specifically an exception specified below) if the move is invalid or illegal in the current position (but not a null move). - - :exc:`InvalidMoveError` if the UCI is syntactically invalid. - - :exc:`IllegalMoveError` if the UCI is illegal. + + - :exc:`InvalidMoveError` if the UCI is syntactically invalid. + - :exc:`IllegalMoveError` if the UCI is illegal. """ move = self.parse_uci(uci) self.push(move) From d7c3edb0e69fe42db978982e93f0694a9e519f7b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 7 Jan 2023 20:02:27 +0100 Subject: [PATCH 005/250] Close Syzygy table file descriptors after mmap --- chess/syzygy.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 0266ea422..28cc9c4d0 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -559,7 +559,6 @@ def __init__(self, path: str, *, variant: Type[chess.Board] = chess.Board) -> No self.write_lock = threading.RLock() self.initialized = False - self.fd: Optional[int] = None self.data: Optional[mmap.mmap] = None self.read_condition = threading.Condition() @@ -602,23 +601,29 @@ def __init__(self, path: str, *, variant: Type[chess.Board] = chess.Board) -> No self.enc_type = 1 + j def init_mmap(self) -> None: + if self.data is not None: + return + with self.write_lock: - # Open fd. - if self.fd is None: - self.fd = os.open(self.path, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) + if self.data is not None: + return + + fd = os.open(self.path, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) + try: + data = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) + finally: + os.close(fd) - # Open mmap. - if self.data is None: - data = mmap.mmap(self.fd, 0, access=mmap.ACCESS_READ) - if data.size() % 64 != 16: - raise IOError(f"invalid file size: ensure {self.path!r} is a valid syzygy tablebase file") - self.data = data + if data.size() % 64 != 16: + raise IOError(f"invalid file size: ensure {self.path!r} is a valid syzygy tablebase file") - try: - # Python 3.8 - self.data.madvise(mmap.MADV_RANDOM) - except AttributeError: - pass + try: + # Python 3.8 + data.madvise(mmap.MADV_RANDOM) + except AttributeError: + pass + + self.data = data def check_magic(self, magic: Optional[bytes], pawnless_magic: Optional[bytes]) -> None: assert self.data @@ -1045,10 +1050,6 @@ def close(self) -> None: self.data.close() self.data = None - if self.fd is not None: - os.close(self.fd) - self.fd = None - def __enter__(self: TableT) -> TableT: return self From 9cb8d3ba11183713314f817f6b6ccef18d1bde88 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 7 Jan 2023 20:05:56 +0100 Subject: [PATCH 006/250] Close PolyGlot file descriptors after mmap --- chess/polyglot.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/chess/polyglot.py b/chess/polyglot.py index 1562d5306..c56c5ecfb 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -337,12 +337,13 @@ class MemoryMappedReader: """Maps a Polyglot opening book to memory.""" def __init__(self, filename: PathLike) -> None: - self.fd = os.open(filename, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) - + fd = os.open(filename, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) try: - self.mmap: Union[mmap.mmap, _EmptyMmap] = mmap.mmap(self.fd, 0, access=mmap.ACCESS_READ) + self.mmap: Union[mmap.mmap, _EmptyMmap] = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) except (ValueError, OSError): self.mmap = _EmptyMmap() # Workaround for empty opening books. + finally: + os.close(fd) if self.mmap.size() % ENTRY_STRUCT.size != 0: raise IOError(f"invalid file size: ensure {filename!r} is a valid polyglot opening book") @@ -514,11 +515,6 @@ def close(self) -> None: """Closes the reader.""" self.mmap.close() - try: - os.close(self.fd) - except OSError: - pass - def open_reader(path: PathLike) -> MemoryMappedReader: """ From 3fd11884ee0ae114ab243d9f66da500dff6b9bf6 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 7 Jan 2023 20:20:28 +0100 Subject: [PATCH 007/250] Simplify syzygy.Table.init_mmap() --- chess/syzygy.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 28cc9c4d0..4fe070c91 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -601,13 +601,7 @@ def __init__(self, path: str, *, variant: Type[chess.Board] = chess.Board) -> No self.enc_type = 1 + j def init_mmap(self) -> None: - if self.data is not None: - return - - with self.write_lock: - if self.data is not None: - return - + if self.data is None: fd = os.open(self.path, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) try: data = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) From ebb7b3987715a889f18d0d65382a1f162c261901 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 7 Jan 2023 20:56:50 +0100 Subject: [PATCH 008/250] Change default of Tablebase.max_fds to None This is compatible thanks to the new implementation, which does not keep open file descriptors around in any case. --- chess/syzygy.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 4fe070c91..45eb963d0 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1482,12 +1482,8 @@ def setup_pieces_pawn_dtz(self, p_data: int, p_tb_size: int, f: int) -> None: class Tablebase: """ Manages a collection of tablebase files for probing. - - If *max_fds* is not ``None``, will at most use *max_fds* open file - descriptors at any given time. The least recently used tables are closed, - if necessary. """ - def __init__(self, *, max_fds: Optional[int] = 128, VariantBoard: Type[chess.Board] = chess.Board) -> None: + def __init__(self, *, max_fds: Optional[int] = None, VariantBoard: Type[chess.Board] = chess.Board) -> None: self.variant = VariantBoard self.max_fds = max_fds @@ -1967,7 +1963,7 @@ def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[ self.close() -def open_tablebase(directory: str, *, load_wdl: bool = True, load_dtz: bool = True, max_fds: Optional[int] = 128, VariantBoard: Type[chess.Board] = chess.Board) -> Tablebase: +def open_tablebase(directory: str, *, load_wdl: bool = True, load_dtz: bool = True, max_fds: Optional[int] = None, VariantBoard: Type[chess.Board] = chess.Board) -> Tablebase: """ Opens a collection of tables for probing. See :class:`~chess.syzygy.Tablebase`. @@ -1981,6 +1977,10 @@ def open_tablebase(directory: str, *, load_wdl: bool = True, load_dtz: bool = Tr are often distributed separately, but are both required for 6-piece positions. Use :func:`~chess.syzygy.Tablebase.add_directory()` to load tables from additional directories. + + :param max_fds: If *max_fds* is not ``None``, will at most use *max_fds* + open file descriptors at any given time. The least recently used tables + are closed, if necessary. """ tables = Tablebase(max_fds=max_fds, VariantBoard=VariantBoard) tables.add_directory(directory, load_wdl=load_wdl, load_dtz=load_dtz) From 1985e6d5acce645354c5c6c8d7d65c0499715953 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 7 Jan 2023 21:09:58 +0100 Subject: [PATCH 009/250] Bump Sphinx to 6.1.2 --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index f18b82961..8f65fe1fd 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -Sphinx==6.1.1 +Sphinx==6.1.2 From 57fce306c93a22c00d3b91cea68c618683987df3 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 20 Jan 2023 20:53:24 +0100 Subject: [PATCH 010/250] Add chess960.perft --- .github/workflows/test.yml | 1 + examples/perft/chess960.perft | 8641 +++++++++++++++++++++++++++++++++ 2 files changed, 8642 insertions(+) create mode 100644 examples/perft/chess960.perft diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 68ab5bb19..95e9a3728 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,6 +27,7 @@ jobs: python-version: "3.11" - run: pip install -e . - run: python examples/perft/perft.py -t 1 examples/perft/random.perft --max-nodes 10000 + - run: python examples/perft/perft.py -t 1 examples/perft/chess960.perft --max-nodes 100000 - run: python examples/perft/perft.py -t 1 examples/perft/tricky.perft - run: python examples/perft/perft.py -t 1 --variant giveaway examples/perft/giveaway.perft - run: python examples/perft/perft.py -t 1 --variant atomic examples/perft/atomic.perft diff --git a/examples/perft/chess960.perft b/examples/perft/chess960.perft new file mode 100644 index 000000000..0d14d5da0 --- /dev/null +++ b/examples/perft/chess960.perft @@ -0,0 +1,8641 @@ +# https://www.chessprogramming.org/Chess960_Perft_Results + +id 1 +epd bqnb1rkr/pp3ppp/3ppn2/2p5/5P2/P2P4/NPP1P1PP/BQ1BNRKR w HFhf - 2 9 +perft 1 21 +perft 2 528 +perft 3 12189 +perft 4 326672 +perft 5 8146062 +perft 6 227689589 + +id 1 +epd 2nnrbkr/p1qppppp/8/1ppb4/6PP/3PP3/PPP2P2/BQNNRBKR w HEhe - 1 9 +perft 1 21 +perft 2 807 +perft 3 18002 +perft 4 667366 +perft 5 16253601 +perft 6 590751109 + +id 1 +epd b1q1rrkb/pppppppp/3nn3/8/P7/1PPP4/4PPPP/BQNNRKRB w GE - 1 9 +perft 1 20 +perft 2 479 +perft 3 10471 +perft 4 273318 +perft 5 6417013 +perft 6 177654692 + +id 1 +epd qbbnnrkr/2pp2pp/p7/1p2pp2/8/P3PP2/1PPP1KPP/QBBNNR1R w hf - 0 9 +perft 1 22 +perft 2 593 +perft 3 13440 +perft 4 382958 +perft 5 9183776 +perft 6 274103539 + +id 1 +epd 1nbbnrkr/p1p1ppp1/3p4/1p3P1p/3Pq2P/8/PPP1P1P1/QNBBNRKR w HFhf - 0 9 +perft 1 28 +perft 2 1120 +perft 3 31058 +perft 4 1171749 +perft 5 34030312 +perft 6 1250970898 + +id 1 +epd qnbnr1kr/ppp1b1pp/4p3/3p1p2/8/2NPP3/PPP1BPPP/QNB1R1KR w HEhe - 1 9 +perft 1 29 +perft 2 899 +perft 3 26578 +perft 4 824055 +perft 5 24851983 +perft 6 775718317 + +id 1 +epd q1bnrkr1/ppppp2p/2n2p2/4b1p1/2NP4/8/PPP1PPPP/QNB1RRKB w ge - 1 9 +perft 1 30 +perft 2 860 +perft 3 24566 +perft 4 732757 +perft 5 21093346 +perft 6 649209803 + +id 1 +epd qbn1brkr/ppp1p1p1/2n4p/3p1p2/P7/6PP/QPPPPP2/1BNNBRKR w HFhf - 0 9 +perft 1 25 +perft 2 635 +perft 3 17054 +perft 4 465806 +perft 5 13203304 +perft 6 377184252 + +id 1 +epd qnnbbrkr/1p2ppp1/2pp3p/p7/1P5P/2NP4/P1P1PPP1/Q1NBBRKR w HFhf - 0 9 +perft 1 24 +perft 2 572 +perft 3 15243 +perft 4 384260 +perft 5 11110203 +perft 6 293989890 + +id 1 +epd qn1rbbkr/ppp2p1p/1n1pp1p1/8/3P4/P6P/1PP1PPPK/QNNRBB1R w hd - 2 9 +perft 1 28 +perft 2 811 +perft 3 23175 +perft 4 679699 +perft 5 19836606 +perft 6 594527992 + +id 1 +epd qnr1bkrb/pppp2pp/3np3/5p2/8/P2P2P1/NPP1PP1P/QN1RBKRB w GDg - 3 9 +perft 1 33 +perft 2 823 +perft 3 26895 +perft 4 713420 +perft 5 23114629 +perft 6 646390782 + +id 1 +epd qb1nrkbr/1pppp1p1/1n3p2/p1B4p/8/3P1P1P/PPP1P1P1/QBNNRK1R w HEhe - 0 9 +perft 1 31 +perft 2 855 +perft 3 25620 +perft 4 735703 +perft 5 21796206 +perft 6 651054626 + +id 1 +epd qnnbrk1r/1p1ppbpp/2p5/p4p2/2NP3P/8/PPP1PPP1/Q1NBRKBR w HEhe - 0 9 +perft 1 26 +perft 2 790 +perft 3 21238 +perft 4 642367 +perft 5 17819770 +perft 6 544866674 + +id 1 +epd 1qnrkbbr/1pppppp1/p1n4p/8/P7/1P1N1P2/2PPP1PP/QN1RKBBR w HDhd - 0 9 +perft 1 37 +perft 2 883 +perft 3 32187 +perft 4 815535 +perft 5 29370838 +perft 6 783201510 + +id 1 +epd qn1rkrbb/pp1p1ppp/2p1p3/3n4/4P2P/2NP4/PPP2PP1/Q1NRKRBB w FDfd - 1 9 +perft 1 24 +perft 2 585 +perft 3 14769 +perft 4 356950 +perft 5 9482310 +perft 6 233468620 + +id 1 +epd bb1qnrkr/pp1p1pp1/1np1p3/4N2p/8/1P4P1/P1PPPP1P/BBNQ1RKR w HFhf - 0 9 +perft 1 29 +perft 2 864 +perft 3 25747 +perft 4 799727 +perft 5 24219627 +perft 6 776836316 + +id 1 +epd bnqbnr1r/p1p1ppkp/3p4/1p4p1/P7/3NP2P/1PPP1PP1/BNQB1RKR w HF - 0 9 +perft 1 26 +perft 2 889 +perft 3 24353 +perft 4 832956 +perft 5 23701014 +perft 6 809194268 + +id 1 +epd bnqnrbkr/1pp2pp1/p7/3pP2p/4P1P1/8/PPPP3P/BNQNRBKR w HEhe d6 0 9 +perft 1 31 +perft 2 984 +perft 3 28677 +perft 4 962591 +perft 5 29032175 +perft 6 1008880643 + +id 1 +epd b1qnrrkb/ppp1pp1p/n2p1Pp1/8/8/P7/1PPPP1PP/BNQNRKRB w GE - 0 9 +perft 1 20 +perft 2 484 +perft 3 10532 +perft 4 281606 +perft 5 6718715 +perft 6 193594729 + +id 1 +epd n1bqnrkr/pp1ppp1p/2p5/6p1/2P2b2/PN6/1PNPPPPP/1BBQ1RKR w HFhf - 2 9 +perft 1 23 +perft 2 732 +perft 3 17746 +perft 4 558191 +perft 5 14481581 +perft 6 457140569 + +id 1 +epd n1bb1rkr/qpnppppp/2p5/p7/P1P5/5P2/1P1PPRPP/NQBBN1KR w Hhf - 1 9 +perft 1 27 +perft 2 697 +perft 3 18724 +perft 4 505089 +perft 5 14226907 +perft 6 400942568 + +id 1 +epd nqb1rbkr/pppppp1p/4n3/6p1/4P3/1NP4P/PP1P1PP1/1QBNRBKR w HEhe - 1 9 +perft 1 28 +perft 2 641 +perft 3 18811 +perft 4 456916 +perft 5 13780398 +perft 6 354122358 + +id 1 +epd n1bnrrkb/pp1pp2p/2p2p2/6p1/5B2/3P4/PPP1PPPP/NQ1NRKRB w GE - 2 9 +perft 1 28 +perft 2 606 +perft 3 16883 +perft 4 381646 +perft 5 10815324 +perft 6 254026570 + +id 1 +epd nbqnbrkr/2ppp1p1/pp3p1p/8/4N2P/1N6/PPPPPPP1/1BQ1BRKR w HFhf - 0 9 +perft 1 26 +perft 2 626 +perft 3 17268 +perft 4 437525 +perft 5 12719546 +perft 6 339132046 + +id 1 +epd nq1bbrkr/pp2nppp/2pp4/4p3/1PP1P3/1B6/P2P1PPP/NQN1BRKR w HFhf - 2 9 +perft 1 21 +perft 2 504 +perft 3 11812 +perft 4 302230 +perft 5 7697880 +perft 6 207028745 + +id 1 +epd nqnrb1kr/2pp1ppp/1p1bp3/p1B5/5P2/3N4/PPPPP1PP/NQ1R1BKR w HDhd - 0 9 +perft 1 30 +perft 2 672 +perft 3 19307 +perft 4 465317 +perft 5 13454573 +perft 6 345445468 + +id 1 +epd nqn2krb/p1prpppp/1pbp4/7P/5P2/8/PPPPPKP1/NQNRB1RB w g - 3 9 +perft 1 21 +perft 2 461 +perft 3 10608 +perft 4 248069 +perft 5 6194124 +perft 6 152861936 + +id 1 +epd nb1n1kbr/ppp1rppp/3pq3/P3p3/8/4P3/1PPPRPPP/NBQN1KBR w Hh - 1 9 +perft 1 19 +perft 2 566 +perft 3 11786 +perft 4 358337 +perft 5 8047916 +perft 6 249171636 + +id 1 +epd nqnbrkbr/1ppppp1p/p7/6p1/6P1/P6P/1PPPPP2/NQNBRKBR w HEhe - 1 9 +perft 1 20 +perft 2 382 +perft 3 8694 +perft 4 187263 +perft 5 4708975 +perft 6 112278808 + +id 1 +epd nq1rkb1r/pp1pp1pp/1n2bp1B/2p5/8/5P1P/PPPPP1P1/NQNRKB1R w HDhd - 2 9 +perft 1 24 +perft 2 809 +perft 3 20090 +perft 4 673811 +perft 5 17647882 +perft 6 593457788 + +id 1 +epd nqnrkrb1/pppppp2/7p/4b1p1/8/PN1NP3/1PPP1PPP/1Q1RKRBB w FDfd - 1 9 +perft 1 26 +perft 2 683 +perft 3 18102 +perft 4 473911 +perft 5 13055173 +perft 6 352398011 + +id 1 +epd bb1nqrkr/1pp1ppp1/pn5p/3p4/8/P2NNP2/1PPPP1PP/BB2QRKR w HFhf - 0 9 +perft 1 29 +perft 2 695 +perft 3 21193 +perft 4 552634 +perft 5 17454857 +perft 6 483785639 + +id 1 +epd bnn1qrkr/pp1ppp1p/2p5/b3Q1p1/8/5P1P/PPPPP1P1/BNNB1RKR w HFhf - 2 9 +perft 1 44 +perft 2 920 +perft 3 35830 +perft 4 795317 +perft 5 29742670 +perft 6 702867204 + +id 1 +epd bnnqrbkr/pp1p2p1/2p1p2p/5p2/1P5P/1R6/P1PPPPP1/BNNQRBK1 w Ehe - 0 9 +perft 1 33 +perft 2 1022 +perft 3 32724 +perft 4 1024721 +perft 5 32898113 +perft 6 1047360456 + +id 1 +epd b1nqrkrb/2pppppp/p7/1P6/1n6/P4P2/1P1PP1PP/BNNQRKRB w GEge - 0 9 +perft 1 23 +perft 2 638 +perft 3 15744 +perft 4 446539 +perft 5 11735969 +perft 6 344211589 + +id 1 +epd n1bnqrkr/3ppppp/1p6/pNp1b3/2P3P1/8/PP1PPP1P/NBB1QRKR w HFhf - 1 9 +perft 1 29 +perft 2 728 +perft 3 20768 +perft 4 532084 +perft 5 15621236 +perft 6 415766465 + +id 1 +epd n2bqrkr/p1p1pppp/1pn5/3p1b2/P6P/1NP5/1P1PPPP1/1NBBQRKR w HFhf - 3 9 +perft 1 20 +perft 2 533 +perft 3 12152 +perft 4 325059 +perft 5 8088751 +perft 6 223068417 + +id 1 +epd nnbqrbkr/1pp1p1p1/p2p4/5p1p/2P1P3/N7/PPQP1PPP/N1B1RBKR w HEhe - 0 9 +perft 1 27 +perft 2 619 +perft 3 18098 +perft 4 444421 +perft 5 13755384 +perft 6 357222394 + +id 1 +epd nnbqrkr1/pp1pp2p/2p2b2/5pp1/1P5P/4P1P1/P1PP1P2/NNBQRKRB w GEge - 1 9 +perft 1 32 +perft 2 1046 +perft 3 33721 +perft 4 1111186 +perft 5 36218182 +perft 6 1202830851 + +id 1 +epd nb1qbrkr/p1pppp2/1p1n2pp/8/1P6/2PN3P/P2PPPP1/NB1QBRKR w HFhf - 0 9 +perft 1 25 +perft 2 521 +perft 3 14021 +perft 4 306427 +perft 5 8697700 +perft 6 201455191 + +id 1 +epd nnq1brkr/pp1pppp1/8/2p4P/8/5K2/PPPbPP1P/NNQBBR1R w hf - 0 9 +perft 1 23 +perft 2 724 +perft 3 18263 +perft 4 571072 +perft 5 15338230 +perft 6 484638597 + +id 1 +epd nnqrbb1r/pppppk2/5pp1/7p/1P6/3P2PP/P1P1PP2/NNQRBBKR w HD - 0 9 +perft 1 30 +perft 2 717 +perft 3 21945 +perft 4 547145 +perft 5 17166700 +perft 6 450069742 + +id 1 +epd nnqr1krb/p1p1pppp/2bp4/8/1p1P4/4P3/PPP2PPP/NNQRBKRB w GDgd - 0 9 +perft 1 25 +perft 2 873 +perft 3 20796 +perft 4 728628 +perft 5 18162741 +perft 6 641708630 + +id 1 +epd nbnqrkbr/p2ppp2/1p4p1/2p4p/3P3P/3N4/PPP1PPPR/NB1QRKB1 w Ehe - 0 9 +perft 1 24 +perft 2 589 +perft 3 15190 +perft 4 382317 +perft 5 10630667 +perft 6 279474189 + +id 1 +epd n1qbrkbr/p1ppp2p/2n2pp1/1p6/1P6/2P3P1/P2PPP1P/NNQBRKBR w HEhe - 0 9 +perft 1 22 +perft 2 592 +perft 3 14269 +perft 4 401976 +perft 5 10356818 +perft 6 301583306 + +id 1 +epd 2qrkbbr/ppn1pppp/n1p5/3p4/5P2/P1PP4/1P2P1PP/NNQRKBBR w HDhd - 1 9 +perft 1 27 +perft 2 750 +perft 3 20584 +perft 4 605458 +perft 5 16819085 +perft 6 516796736 + +id 1 +epd 1nqr1rbb/pppkp1pp/1n3p2/3p4/1P6/5P1P/P1PPPKP1/NNQR1RBB w - - 1 9 +perft 1 24 +perft 2 623 +perft 3 15921 +perft 4 429446 +perft 5 11594634 +perft 6 322745925 + +id 1 +epd bbn1rqkr/pp1pp2p/4npp1/2p5/1P6/2BPP3/P1P2PPP/1BNNRQKR w HEhe - 0 9 +perft 1 23 +perft 2 730 +perft 3 17743 +perft 4 565340 +perft 5 14496370 +perft 6 468608864 + +id 1 +epd bn1brqkr/pppp2p1/3npp2/7p/PPP5/8/3PPPPP/BNNBRQKR w HEhe - 0 9 +perft 1 25 +perft 2 673 +perft 3 17835 +perft 4 513696 +perft 5 14284338 +perft 6 434008567 + +id 1 +epd bn1rqbkr/ppp1ppp1/1n6/2p4p/7P/3P4/PPP1PPP1/BN1RQBKR w HDhd - 0 9 +perft 1 25 +perft 2 776 +perft 3 20562 +perft 4 660217 +perft 5 18486027 +perft 6 616653869 + +id 1 +epd bnnr1krb/ppp2ppp/3p4/3Bp3/q1P3PP/8/PP1PPP2/BNNRQKR1 w GDgd - 0 9 +perft 1 29 +perft 2 1040 +perft 3 30772 +perft 4 1053113 +perft 5 31801525 +perft 6 1075147725 + +id 1 +epd 1bbnrqkr/pp1ppppp/8/2p5/n7/3PNPP1/PPP1P2P/NBB1RQKR w HEhe - 1 9 +perft 1 24 +perft 2 598 +perft 3 15673 +perft 4 409766 +perft 5 11394778 +perft 6 310589129 + +id 1 +epd nnbbrqkr/p2ppp1p/1pp5/8/6p1/N1P5/PPBPPPPP/N1B1RQKR w HEhe - 0 9 +perft 1 26 +perft 2 530 +perft 3 14031 +perft 4 326312 +perft 5 8846766 +perft 6 229270702 + +id 1 +epd nnbrqbkr/2p1p1pp/p4p2/1p1p4/8/NP6/P1PPPPPP/N1BRQBKR w HDhd - 0 9 +perft 1 17 +perft 2 496 +perft 3 10220 +perft 4 303310 +perft 5 7103549 +perft 6 217108001 + +id 1 +epd nnbrqk1b/pp2pprp/2pp2p1/8/3PP1P1/8/PPP2P1P/NNBRQRKB w d - 1 9 +perft 1 33 +perft 2 820 +perft 3 27856 +perft 4 706784 +perft 5 24714401 +perft 6 645835197 + +id 1 +epd 1bnrbqkr/ppnpp1p1/2p2p1p/8/1P6/4PPP1/P1PP3P/NBNRBQKR w HDhd - 0 9 +perft 1 27 +perft 2 705 +perft 3 19760 +perft 4 548680 +perft 5 15964771 +perft 6 464662032 + +id 1 +epd n1rbbqkr/pp1pppp1/7p/P1p5/1n6/2PP4/1P2PPPP/NNRBBQKR w HChc - 0 9 +perft 1 22 +perft 2 631 +perft 3 14978 +perft 4 431801 +perft 5 10911545 +perft 6 320838556 + +id 1 +epd n1rqb1kr/p1pppp1p/1pn4b/3P2p1/P7/1P6/2P1PPPP/NNRQBBKR w HChc - 0 9 +perft 1 24 +perft 2 477 +perft 3 12506 +perft 4 263189 +perft 5 7419372 +perft 6 165945904 + +id 1 +epd nnrqbkrb/pppp1pp1/7p/4p3/6P1/2N2B2/PPPPPP1P/NR1QBKR1 w Ggc - 2 9 +perft 1 29 +perft 2 658 +perft 3 19364 +perft 4 476620 +perft 5 14233587 +perft 6 373744834 + +id 1 +epd n1nrqkbr/ppb2ppp/3pp3/2p5/2P3P1/5P2/PP1PPB1P/NBNRQK1R w HDhd - 1 9 +perft 1 32 +perft 2 801 +perft 3 25861 +perft 4 681428 +perft 5 22318948 +perft 6 619857455 + +id 1 +epd 2rbqkbr/p1pppppp/1nn5/1p6/7P/P4P2/1PPPP1PB/NNRBQK1R w HChc - 2 9 +perft 1 27 +perft 2 647 +perft 3 18030 +perft 4 458057 +perft 5 13189156 +perft 6 354689323 + +id 1 +epd nn1qkbbr/pp2ppp1/2rp4/2p4p/P2P4/1N5P/1PP1PPP1/1NRQKBBR w HCh - 1 9 +perft 1 24 +perft 2 738 +perft 3 18916 +perft 4 586009 +perft 5 16420659 +perft 6 519075930 + +id 1 +epd nnrqk1bb/p1ppp2p/5rp1/1p3p2/1P4P1/5P1P/P1PPP3/NNRQKRBB w FCc - 1 9 +perft 1 25 +perft 2 795 +perft 3 20510 +perft 4 648945 +perft 5 17342527 +perft 6 556144017 + +id 1 +epd bb1nrkqr/ppppn2p/4ppp1/8/1P4P1/4P3/P1PPKP1P/BBNNR1QR w he - 0 9 +perft 1 29 +perft 2 664 +perft 3 20024 +perft 4 498376 +perft 5 15373803 +perft 6 406016364 + +id 1 +epd bnnbrkqr/1p1ppp2/8/p1p3pp/1P6/N4P2/PBPPP1PP/2NBRKQR w HEhe - 0 9 +perft 1 31 +perft 2 770 +perft 3 24850 +perft 4 677212 +perft 5 22562080 +perft 6 662029574 + +id 1 +epd 1nnrkbqr/p1pp1ppp/4p3/1p6/1Pb1P3/6PB/P1PP1P1P/BNNRK1QR w HDhd - 0 9 +perft 1 27 +perft 2 776 +perft 3 22133 +perft 4 641002 +perft 5 19153245 +perft 6 562738257 + +id 1 +epd bnr1kqrb/pppp1pp1/1n5p/4p3/P3P3/3P2P1/1PP2P1P/BNNRKQRB w GDg - 0 9 +perft 1 26 +perft 2 624 +perft 3 16411 +perft 4 435426 +perft 5 11906515 +perft 6 338092952 + +id 1 +epd nbbnrkqr/p1ppp1pp/1p3p2/8/2P5/4P3/PP1P1PPP/NBBNRKQR w HEhe - 1 9 +perft 1 25 +perft 2 624 +perft 3 15561 +perft 4 419635 +perft 5 10817378 +perft 6 311138112 + +id 1 +epd nn1brkqr/pp1bpppp/8/2pp4/P4P2/1PN5/2PPP1PP/N1BBRKQR w HEhe - 1 9 +perft 1 23 +perft 2 659 +perft 3 16958 +perft 4 476567 +perft 5 13242252 +perft 6 373557073 + +id 1 +epd n1brkbqr/ppp1pp1p/6pB/3p4/2Pn4/8/PP2PPPP/NN1RKBQR w HDhd - 0 9 +perft 1 32 +perft 2 1026 +perft 3 30360 +perft 4 978278 +perft 5 29436320 +perft 6 957904151 + +id 1 +epd nnbrkqrb/p2ppp2/Q5pp/1pp5/4PP2/2N5/PPPP2PP/N1BRK1RB w GDgd - 0 9 +perft 1 36 +perft 2 843 +perft 3 29017 +perft 4 715537 +perft 5 24321197 +perft 6 630396940 + +id 1 +epd nbnrbk1r/pppppppq/8/7p/8/1N2QPP1/PPPPP2P/NB1RBK1R w HDhd - 2 9 +perft 1 36 +perft 2 973 +perft 3 35403 +perft 4 1018054 +perft 5 37143354 +perft 6 1124883780 + +id 1 +epd nnrbbkqr/2pppp1p/p7/6p1/1p2P3/4QPP1/PPPP3P/NNRBBK1R w HChc - 0 9 +perft 1 36 +perft 2 649 +perft 3 22524 +perft 4 489526 +perft 5 16836636 +perft 6 416139320 + +id 1 +epd nnrkbbqr/1p2pppp/p2p4/2p5/8/1N2P1P1/PPPP1P1P/1NKRBBQR w hc - 0 9 +perft 1 26 +perft 2 672 +perft 3 18136 +perft 4 477801 +perft 5 13342771 +perft 6 363074681 + +id 1 +epd n1rkbqrb/pp1ppp2/2n3p1/2p4p/P5PP/1P6/2PPPP2/NNRKBQRB w GCgc - 0 9 +perft 1 24 +perft 2 804 +perft 3 20712 +perft 4 684001 +perft 5 18761475 +perft 6 617932151 + +id 1 +epd nbkr1qbr/1pp1pppp/pn1p4/8/3P2P1/5R2/PPP1PP1P/NBN1KQBR w H - 2 9 +perft 1 30 +perft 2 627 +perft 3 18669 +perft 4 423329 +perft 5 12815016 +perft 6 312798696 + +id 1 +epd nnr1kqbr/pp1pp1p1/2p5/b4p1p/P7/1PNP4/2P1PPPP/N1RBKQBR w HChc - 1 9 +perft 1 12 +perft 2 421 +perft 3 6530 +perft 4 227044 +perft 5 4266410 +perft 6 149176979 + +id 1 +epd n1rkqbbr/p1pp1pp1/np2p2p/8/8/N4PP1/PPPPP1BP/N1RKQ1BR w HChc - 0 9 +perft 1 27 +perft 2 670 +perft 3 19119 +perft 4 494690 +perft 5 14708490 +perft 6 397268628 + +id 1 +epd nnr1qrbb/p2kpppp/1p1p4/2p5/6P1/PP1P4/2P1PP1P/NNRKQRBB w FC - 0 9 +perft 1 27 +perft 2 604 +perft 3 17043 +perft 4 409665 +perft 5 11993332 +perft 6 308518181 + +id 1 +epd bbnnrkrq/ppp1pp2/6p1/3p4/7p/7P/PPPPPPP1/BBNNRRKQ w ge - 0 9 +perft 1 20 +perft 2 559 +perft 3 12242 +perft 4 355326 +perft 5 8427161 +perft 6 252274233 + +id 1 +epd bnnbrkr1/ppp2p1p/5q2/3pp1p1/4P3/1N4P1/PPPPRP1P/BN1B1KRQ w Gge - 0 9 +perft 1 26 +perft 2 1036 +perft 3 27228 +perft 4 1028084 +perft 5 28286576 +perft 6 1042120495 + +id 1 +epd bn1rkbrq/1pppppp1/p6p/1n6/3P4/6PP/PPPRPP2/BNN1KBRQ w Ggd - 2 9 +perft 1 29 +perft 2 633 +perft 3 19278 +perft 4 455476 +perft 5 14333034 +perft 6 361900466 + +id 1 +epd b1nrkrqb/1p1npppp/p2p4/2p5/5P2/4P2P/PPPP1RP1/BNNRK1QB w Dfd - 1 9 +perft 1 25 +perft 2 475 +perft 3 12603 +perft 4 270909 +perft 5 7545536 +perft 6 179579818 + +id 1 +epd 1bbnrkrq/ppppppp1/8/7p/1n4P1/1PN5/P1PPPP1P/NBBR1KRQ w Gge - 0 9 +perft 1 30 +perft 2 803 +perft 3 25473 +perft 4 709716 +perft 5 23443854 +perft 6 686365049 + +id 1 +epd nnbbrkrq/2pp1pp1/1p5p/pP2p3/7P/N7/P1PPPPP1/N1BBRKRQ w GEge - 0 9 +perft 1 18 +perft 2 432 +perft 3 9638 +perft 4 242350 +perft 5 6131124 +perft 6 160393505 + +id 1 +epd nnbrkbrq/1pppp1p1/p7/7p/1P2Pp2/BN6/P1PP1PPP/1N1RKBRQ w GDgd - 0 9 +perft 1 27 +perft 2 482 +perft 3 13441 +perft 4 282259 +perft 5 8084701 +perft 6 193484216 + +id 1 +epd n1brkrqb/pppp3p/n3pp2/6p1/3P1P2/N1P5/PP2P1PP/N1BRKRQB w FDfd - 0 9 +perft 1 28 +perft 2 642 +perft 3 19005 +perft 4 471729 +perft 5 14529434 +perft 6 384837696 + +id 1 +epd nbnrbk2/p1pppp1p/1p3qr1/6p1/1B1P4/1N6/PPP1PPPP/1BNR1RKQ w d - 2 9 +perft 1 30 +perft 2 796 +perft 3 22780 +perft 4 687302 +perft 5 20120565 +perft 6 641832725 + +id 1 +epd nnrbbrkq/1pp2ppp/3p4/p3p3/3P1P2/1P2P3/P1P3PP/NNRBBKRQ w GC - 1 9 +perft 1 31 +perft 2 827 +perft 3 24538 +perft 4 663082 +perft 5 19979594 +perft 6 549437308 + +id 1 +epd nnrkbbrq/1pp2p1p/p2pp1p1/2P5/8/8/PP1PPPPP/NNRKBBRQ w Ggc - 0 9 +perft 1 24 +perft 2 762 +perft 3 19283 +perft 4 624598 +perft 5 16838099 +perft 6 555230555 + +id 1 +epd nnr1brqb/1ppkp1pp/8/p2p1p2/1P1P4/N1P5/P3PPPP/N1RKBRQB w FC - 1 9 +perft 1 23 +perft 2 640 +perft 3 15471 +perft 4 444905 +perft 5 11343507 +perft 6 334123513 + +id 1 +epd nbnrkrbq/2ppp2p/p4p2/1P4p1/4PP2/8/1PPP2PP/NBNRKRBQ w FDfd - 0 9 +perft 1 31 +perft 2 826 +perft 3 26137 +perft 4 732175 +perft 5 23555139 +perft 6 686250413 + +id 1 +epd 1nrbkr1q/1pppp1pp/1n6/p4p2/N1b4P/8/PPPPPPPB/N1RBKR1Q w FCfc - 2 9 +perft 1 27 +perft 2 862 +perft 3 24141 +perft 4 755171 +perft 5 22027695 +perft 6 696353497 + +id 1 +epd nnrkrbbq/pppp2pp/8/4pp2/4P3/P7/1PPPBPPP/NNKRR1BQ w c - 0 9 +perft 1 25 +perft 2 792 +perft 3 19883 +perft 4 636041 +perft 5 16473376 +perft 6 532214177 + +id 1 +epd n1rk1qbb/pppprpp1/2n4p/4p3/2PP3P/8/PP2PPP1/NNRKRQBB w ECc - 1 9 +perft 1 25 +perft 2 622 +perft 3 16031 +perft 4 425247 +perft 5 11420973 +perft 6 321855685 + +id 1 +epd bbq1rnkr/pnp1pp1p/1p1p4/6p1/2P5/2Q1P2P/PP1P1PP1/BB1NRNKR w HEhe - 2 9 +perft 1 36 +perft 2 870 +perft 3 30516 +perft 4 811047 +perft 5 28127620 +perft 6 799738334 + +id 1 +epd bq1brnkr/1p1ppp1p/1np5/p5p1/8/1N5P/PPPPPPP1/BQ1BRNKR w HEhe - 0 9 +perft 1 22 +perft 2 588 +perft 3 13524 +perft 4 380068 +perft 5 9359618 +perft 6 273795898 + +id 1 +epd bq1rn1kr/1pppppbp/Nn4p1/8/8/P7/1PPPPPPP/BQ1RNBKR w HDhd - 1 9 +perft 1 24 +perft 2 711 +perft 3 18197 +perft 4 542570 +perft 5 14692779 +perft 6 445827351 + +id 1 +epd bqnr1kr1/pppppp1p/6p1/5n2/4B3/3N2PP/PbPPPP2/BQNR1KR1 w GDgd - 2 9 +perft 1 31 +perft 2 1132 +perft 3 36559 +perft 4 1261476 +perft 5 43256823 +perft 6 1456721391 + +id 1 +epd qbb1rnkr/ppp3pp/4n3/3ppp2/1P3PP1/8/P1PPPN1P/QBB1RNKR w HEhe - 0 9 +perft 1 28 +perft 2 696 +perft 3 20502 +perft 4 541886 +perft 5 16492398 +perft 6 456983120 + +id 1 +epd qnbbr1kr/pp1ppp1p/4n3/6p1/2p3P1/2PP1P2/PP2P2P/QNBBRNKR w HEhe - 0 9 +perft 1 25 +perft 2 655 +perft 3 16520 +perft 4 450189 +perft 5 11767038 +perft 6 335414976 + +id 1 +epd 1nbrnbkr/p1ppp1pp/1p6/5p2/4q1PP/3P4/PPP1PP2/QNBRNBKR w HDhd - 1 9 +perft 1 30 +perft 2 1162 +perft 3 33199 +perft 4 1217278 +perft 5 36048727 +perft 6 1290346802 + +id 1 +epd q1brnkrb/p1pppppp/n7/1p6/P7/3P1P2/QPP1P1PP/1NBRNKRB w GDgd - 0 9 +perft 1 32 +perft 2 827 +perft 3 26106 +perft 4 718243 +perft 5 23143989 +perft 6 673147648 + +id 1 +epd qbnrb1kr/ppp1pp1p/3p4/2n3p1/1P6/6N1/P1PPPPPP/QBNRB1KR w HDhd - 2 9 +perft 1 29 +perft 2 751 +perft 3 23132 +perft 4 610397 +perft 5 19555214 +perft 6 530475036 + +id 1 +epd q1rbbnkr/pppp1p2/2n3pp/2P1p3/3P4/8/PP1NPPPP/Q1RBBNKR w HChc - 2 9 +perft 1 29 +perft 2 806 +perft 3 24540 +perft 4 687251 +perft 5 21694330 +perft 6 619907316 + +id 1 +epd q1r1bbkr/pnpp1ppp/2n1p3/1p6/2P2P2/2N1N3/PP1PP1PP/Q1R1BBKR w HChc - 2 9 +perft 1 32 +perft 2 1017 +perft 3 32098 +perft 4 986028 +perft 5 31204371 +perft 6 958455898 + +id 1 +epd 2rnbkrb/pqppppp1/1pn5/7p/2P5/P1R5/QP1PPPPP/1N1NBKRB w Ggc - 4 9 +perft 1 26 +perft 2 625 +perft 3 16506 +perft 4 434635 +perft 5 11856964 +perft 6 336672890 + +id 1 +epd qbnr1kbr/p2ppppp/2p5/1p6/4n2P/P4N2/1PPP1PP1/QBNR1KBR w HDhd - 0 9 +perft 1 27 +perft 2 885 +perft 3 23828 +perft 4 767273 +perft 5 21855658 +perft 6 706272554 + +id 1 +epd qnrbnk1r/pp1pp2p/5p2/2pbP1p1/3P4/1P6/P1P2PPP/QNRBNKBR w HChc - 0 9 +perft 1 26 +perft 2 954 +perft 3 24832 +perft 4 892456 +perft 5 24415089 +perft 6 866744329 + +id 1 +epd qnrnk1br/p1p2ppp/8/1pbpp3/8/PP2N3/1QPPPPPP/1NR1KBBR w HChc - 0 9 +perft 1 26 +perft 2 783 +perft 3 20828 +perft 4 634267 +perft 5 17477825 +perft 6 539674275 + +id 1 +epd qnrnkrbb/Bpppp2p/6p1/5p2/5P2/3PP3/PPP3PP/QNRNKR1B w FCfc - 1 9 +perft 1 28 +perft 2 908 +perft 3 25730 +perft 4 861240 +perft 5 25251641 +perft 6 869525254 + +id 1 +epd bbnqrn1r/ppppp2k/5p2/6pp/7P/1QP5/PP1PPPP1/B1N1RNKR w HE - 0 9 +perft 1 33 +perft 2 643 +perft 3 21790 +perft 4 487109 +perft 5 16693640 +perft 6 410115900 + +id 1 +epd b1qbrnkr/ppp1pp2/2np4/6pp/4P3/2N4P/PPPP1PP1/BQ1BRNKR w HEhe - 0 9 +perft 1 28 +perft 2 837 +perft 3 24253 +perft 4 745617 +perft 5 22197063 +perft 6 696399065 + +id 1 +epd bnqr1bkr/pp1ppppp/2p5/4N3/5P2/P7/1PPPPnPP/BNQR1BKR w HDhd - 3 9 +perft 1 25 +perft 2 579 +perft 3 13909 +perft 4 341444 +perft 5 8601011 +perft 6 225530258 + +id 1 +epd b1qr1krb/pp1ppppp/n2n4/8/2p5/2P3P1/PP1PPP1P/BNQRNKRB w GDgd - 0 9 +perft 1 28 +perft 2 707 +perft 3 19721 +perft 4 549506 +perft 5 15583376 +perft 6 468399900 + +id 1 +epd nbbqr1kr/1pppp1pp/8/p1n2p2/4P3/PN6/1PPPQPPP/1BB1RNKR w HEhe - 0 9 +perft 1 30 +perft 2 745 +perft 3 23416 +perft 4 597858 +perft 5 19478789 +perft 6 515473678 + +id 1 +epd nqbbrn1r/p1pppp1k/1p4p1/7p/4P3/1R3B2/PPPP1PPP/NQB2NKR w H - 0 9 +perft 1 24 +perft 2 504 +perft 3 13512 +perft 4 317355 +perft 5 9002073 +perft 6 228726497 + +id 1 +epd nqbr1bkr/p1p1ppp1/1p1n4/3pN2p/1P6/8/P1PPPPPP/NQBR1BKR w HDhd - 0 9 +perft 1 29 +perft 2 898 +perft 3 26532 +perft 4 809605 +perft 5 24703467 +perft 6 757166494 + +id 1 +epd nqbrn1rb/pppp1kp1/5p1p/4p3/P4B2/3P2P1/1PP1PP1P/NQ1RNKRB w GD - 0 9 +perft 1 34 +perft 2 671 +perft 3 22332 +perft 4 473110 +perft 5 15556806 +perft 6 353235120 + +id 1 +epd nb1r1nkr/ppp1ppp1/2bp4/7p/3P2qP/P6R/1PP1PPP1/NBQRBNK1 w Dhd - 1 9 +perft 1 38 +perft 2 1691 +perft 3 60060 +perft 4 2526992 +perft 5 88557078 +perft 6 3589649998 + +id 1 +epd n1rbbnkr/1p1pp1pp/p7/2p1qp2/1B3P2/3P4/PPP1P1PP/NQRB1NKR w HChc - 0 9 +perft 1 24 +perft 2 913 +perft 3 21595 +perft 4 807544 +perft 5 19866918 +perft 6 737239330 + +id 1 +epd nqrnbbkr/p2p1p1p/1pp5/1B2p1p1/1P3P2/4P3/P1PP2PP/NQRNB1KR w HChc - 0 9 +perft 1 33 +perft 2 913 +perft 3 30159 +perft 4 843874 +perft 5 28053260 +perft 6 804687975 + +id 1 +epd nqr1bkrb/ppp1pp2/2np2p1/P6p/8/2P4P/1P1PPPP1/NQRNBKRB w GCgc - 0 9 +perft 1 24 +perft 2 623 +perft 3 16569 +perft 4 442531 +perft 5 12681936 +perft 6 351623879 + +id 1 +epd nb1rnkbr/pqppppp1/1p5p/8/1PP4P/8/P2PPPP1/NBQRNKBR w HDhd - 1 9 +perft 1 31 +perft 2 798 +perft 3 24862 +perft 4 694386 +perft 5 22616076 +perft 6 666227466 + +id 1 +epd nqrbnkbr/2p1p1pp/3p4/pp3p2/6PP/3P1N2/PPP1PP2/NQRB1KBR w HChc - 0 9 +perft 1 24 +perft 2 590 +perft 3 14409 +perft 4 383690 +perft 5 9698432 +perft 6 274064911 + +id 1 +epd nqrnkbbr/pp1p1p1p/4p1p1/1p6/8/5P1P/P1PPP1P1/NQRNKBBR w HChc - 0 9 +perft 1 30 +perft 2 1032 +perft 3 31481 +perft 4 1098116 +perft 5 34914919 +perft 6 1233362066 + +id 1 +epd nqrnkrbb/p2ppppp/1p6/2p5/2P3P1/5P2/PP1PPN1P/NQR1KRBB w FCfc - 1 9 +perft 1 30 +perft 2 775 +perft 3 23958 +perft 4 668000 +perft 5 21141738 +perft 6 621142773 + +id 1 +epd bbnrqrk1/pp2pppp/4n3/2pp4/P7/1N5P/BPPPPPP1/B2RQNKR w HD - 2 9 +perft 1 23 +perft 2 708 +perft 3 17164 +perft 4 554089 +perft 5 14343443 +perft 6 481405144 + +id 1 +epd bnr1qnkr/p1pp1p1p/1p4p1/4p1b1/2P1P3/1P6/PB1P1PPP/1NRBQNKR w HChc - 1 9 +perft 1 30 +perft 2 931 +perft 3 29249 +perft 4 921746 +perft 5 30026687 +perft 6 968109774 + +id 1 +epd b1rqnbkr/ppp1ppp1/3p3p/2n5/P3P3/2NP4/1PP2PPP/B1RQNBKR w HChc - 0 9 +perft 1 24 +perft 2 596 +perft 3 15533 +perft 4 396123 +perft 5 11099382 +perft 6 294180723 + +id 1 +epd bnrqnr1b/pp1pkppp/2p1p3/P7/2P5/7P/1P1PPPP1/BNRQNKRB w GC - 0 9 +perft 1 24 +perft 2 572 +perft 3 15293 +perft 4 390903 +perft 5 11208688 +perft 6 302955778 + +id 1 +epd n1brq1kr/bppppppp/p7/8/4P1Pn/8/PPPP1P2/NBBRQNKR w HDhd - 0 9 +perft 1 20 +perft 2 570 +perft 3 13139 +perft 4 371247 +perft 5 9919113 +perft 6 284592289 + +id 1 +epd 1rbbqnkr/ppn1ppp1/3p3p/2p5/3P4/1N4P1/PPPBPP1P/1R1BQNKR w HBhb - 0 9 +perft 1 29 +perft 2 1009 +perft 3 29547 +perft 4 1040816 +perft 5 31059587 +perft 6 1111986835 + +id 1 +epd nrbq2kr/ppppppb1/5n1p/5Pp1/8/P5P1/1PPPP2P/NRBQNBKR w HBhb - 1 9 +perft 1 20 +perft 2 520 +perft 3 11745 +perft 4 316332 +perft 5 7809837 +perft 6 216997152 + +id 1 +epd nrb1nkrb/pp3ppp/1qBpp3/2p5/8/P5P1/1PPPPP1P/NRBQNKR1 w GBgb - 2 9 +perft 1 32 +perft 2 850 +perft 3 25642 +perft 4 734088 +perft 5 21981567 +perft 6 664886187 + +id 1 +epd 1br1bnkr/ppqppp1p/1np3p1/8/1PP4P/4N3/P2PPPP1/NBRQB1KR w HChc - 1 9 +perft 1 32 +perft 2 798 +perft 3 24765 +perft 4 691488 +perft 5 22076141 +perft 6 670296871 + +id 1 +epd nrqbb1kr/1p1pp1pp/2p3n1/p4p2/3PP3/P5N1/1PP2PPP/NRQBB1KR w HBhb - 0 9 +perft 1 32 +perft 2 791 +perft 3 26213 +perft 4 684890 +perft 5 23239122 +perft 6 634260266 + +id 1 +epd nrqn1bkr/ppppp1pp/4b3/8/4P1p1/5P2/PPPP3P/NRQNBBKR w HBhb - 0 9 +perft 1 29 +perft 2 687 +perft 3 20223 +perft 4 506088 +perft 5 15236287 +perft 6 398759980 + +id 1 +epd nrqnbrkb/pppp1p2/4p2p/3B2p1/8/1P4P1/PQPPPP1P/NR1NBKR1 w GB - 0 9 +perft 1 37 +perft 2 764 +perft 3 27073 +perft 4 610950 +perft 5 21284835 +perft 6 514864869 + +id 1 +epd nbrq1kbr/Bp3ppp/2pnp3/3p4/5P2/2P4P/PP1PP1P1/NBRQNK1R w HChc - 0 9 +perft 1 40 +perft 2 1271 +perft 3 48022 +perft 4 1547741 +perft 5 56588117 +perft 6 1850696281 + +id 1 +epd nrqbnkbr/1p2ppp1/p1p4p/3p4/1P6/8/PQPPPPPP/1RNBNKBR w HBhb - 0 9 +perft 1 28 +perft 2 757 +perft 3 23135 +perft 4 668025 +perft 5 21427496 +perft 6 650939962 + +id 1 +epd nrqn1bbr/2ppkppp/4p3/pB6/8/2P1P3/PP1P1PPP/NRQNK1BR w HB - 1 9 +perft 1 27 +perft 2 642 +perft 3 17096 +perft 4 442653 +perft 5 11872805 +perft 6 327545120 + +id 1 +epd nrqnkrb1/p1ppp2p/1p4p1/4bp2/4PP1P/4N3/PPPP2P1/NRQ1KRBB w FBfb - 1 9 +perft 1 27 +perft 2 958 +perft 3 27397 +perft 4 960350 +perft 5 28520172 +perft 6 995356563 + +id 1 +epd 1bnrnqkr/pbpp2pp/8/1p2pp2/P6P/3P1N2/1PP1PPP1/BBNR1QKR w HDhd - 0 9 +perft 1 27 +perft 2 859 +perft 3 23475 +perft 4 773232 +perft 5 21581178 +perft 6 732696327 + +id 1 +epd b1rbnqkr/1pp1ppp1/2n4p/p2p4/5P2/1PBP4/P1P1P1PP/1NRBNQKR w HChc - 0 9 +perft 1 26 +perft 2 545 +perft 3 14817 +perft 4 336470 +perft 5 9537260 +perft 6 233549184 + +id 1 +epd 1nrnqbkr/p1pppppp/1p6/8/2b2P2/P1N5/1PP1P1PP/BNR1QBKR w HChc - 2 9 +perft 1 24 +perft 2 668 +perft 3 17716 +perft 4 494866 +perft 5 14216070 +perft 6 406225409 + +id 1 +epd 1nrnqkrb/2ppp1pp/p7/1p3p2/5P2/N5K1/PPPPP2P/B1RNQ1RB w gc - 0 9 +perft 1 33 +perft 2 725 +perft 3 23572 +perft 4 559823 +perft 5 18547476 +perft 6 471443091 + +id 1 +epd nbbr1qkr/p1pppppp/8/1p1n4/3P4/1N3PP1/PPP1P2P/1BBRNQKR w HDhd - 1 9 +perft 1 28 +perft 2 698 +perft 3 20527 +perft 4 539625 +perft 5 16555068 +perft 6 458045505 + +id 1 +epd 1rbbnqkr/1pnppp1p/p5p1/2p5/2P4P/5P2/PP1PP1PR/NRBBNQK1 w Bhb - 1 9 +perft 1 24 +perft 2 554 +perft 3 14221 +perft 4 362516 +perft 5 9863080 +perft 6 269284081 + +id 1 +epd nrb1qbkr/2pppppp/2n5/p7/2p5/4P3/PPNP1PPP/1RBNQBKR w HBhb - 0 9 +perft 1 23 +perft 2 618 +perft 3 15572 +perft 4 443718 +perft 5 12044358 +perft 6 360311412 + +id 1 +epd nrb1qkrb/2ppppp1/p3n3/1p1B3p/2P5/6P1/PP1PPPRP/NRBNQK2 w Bgb - 2 9 +perft 1 27 +perft 2 593 +perft 3 16770 +perft 4 401967 +perft 5 11806808 +perft 6 303338935 + +id 1 +epd nbrn1qkr/ppp1pp2/3p2p1/3Q3P/b7/8/PPPPPP1P/NBRNB1KR w HChc - 2 9 +perft 1 39 +perft 2 1056 +perft 3 40157 +perft 4 1133446 +perft 5 42201531 +perft 6 1239888683 + +id 1 +epd nr1bbqkr/pp1pp2p/1n3pp1/2p5/8/1P4P1/P1PPPPQP/NRNBBK1R w hb - 0 9 +perft 1 25 +perft 2 585 +perft 3 15719 +perft 4 406544 +perft 5 11582539 +perft 6 320997679 + +id 1 +epd nr2bbkr/ppp1pppp/1n1p4/8/6PP/1NP4q/PP1PPP2/1RNQBBKR w HBhb - 1 9 +perft 1 22 +perft 2 742 +perft 3 15984 +perft 4 545231 +perft 5 13287051 +perft 6 457010195 + +id 1 +epd 1rnqbkrb/ppp1p1p1/1n3p2/3p3p/P6P/4P3/1PPP1PP1/NRNQBRKB w gb - 0 9 +perft 1 22 +perft 2 574 +perft 3 14044 +perft 4 379648 +perft 5 9968830 +perft 6 281344367 + +id 1 +epd nb1rqkbr/1pppp1pp/4n3/p4p2/6PP/5P2/PPPPPN2/NBR1QKBR w HCh - 0 9 +perft 1 25 +perft 2 621 +perft 3 16789 +perft 4 462600 +perft 5 13378840 +perft 6 396575613 + +id 1 +epd nrnbqkbr/2pp2pp/4pp2/pp6/8/1P3P2/P1PPPBPP/NRNBQ1KR w hb - 0 9 +perft 1 25 +perft 2 656 +perft 3 16951 +perft 4 466493 +perft 5 12525939 +perft 6 358763789 + +id 1 +epd nrnqkbbr/ppppp1p1/7p/5p2/8/P4PP1/NPPPP2P/NR1QKBBR w HBhb - 0 9 +perft 1 28 +perft 2 723 +perft 3 20621 +perft 4 547522 +perft 5 15952533 +perft 6 439046803 + +id 1 +epd 1rnqkr1b/ppppp2p/1n3pp1/8/2P3P1/Pb1N4/1P1PPP1P/NR1QKRBB w FBfb - 0 9 +perft 1 26 +perft 2 713 +perft 3 19671 +perft 4 548875 +perft 5 15865528 +perft 6 454532806 + +id 1 +epd bbnrnkqr/1pppp1pp/5p2/p7/7P/1P6/PBPPPPPR/1BNRNKQ1 w D - 2 9 +perft 1 26 +perft 2 649 +perft 3 17834 +perft 4 502279 +perft 5 14375839 +perft 6 435585252 + +id 1 +epd bnrbk1qr/1ppp1ppp/p2np3/8/P7/2N2P2/1PPPP1PP/B1RBNKQR w HC - 0 9 +perft 1 26 +perft 2 621 +perft 3 17569 +perft 4 451452 +perft 5 13514201 +perft 6 364421088 + +id 1 +epd br1nkbqr/ppppppp1/8/n6p/8/N1P2PP1/PP1PP2P/B1RNKBQR w HCh - 1 9 +perft 1 29 +perft 2 664 +perft 3 20182 +perft 4 512316 +perft 5 16125924 +perft 6 442508159 + +id 1 +epd bnr1kqrb/pp1pppp1/2n5/2p5/1P4Pp/4N3/P1PPPP1P/BNKR1QRB w gc - 0 9 +perft 1 36 +perft 2 888 +perft 3 31630 +perft 4 789863 +perft 5 27792175 +perft 6 719015345 + +id 1 +epd 1bbrnkqr/pp1p1ppp/2p1p3/1n6/5P2/3Q4/PPPPP1PP/NBBRNK1R w HDhd - 2 9 +perft 1 36 +perft 2 891 +perft 3 31075 +perft 4 781792 +perft 5 26998966 +perft 6 702903862 + +id 1 +epd nrbbnk1r/pp2pppq/8/2pp3p/3P2P1/1N6/PPP1PP1P/1RBBNKQR w HBhb - 0 9 +perft 1 29 +perft 2 1036 +perft 3 31344 +perft 4 1139166 +perft 5 35627310 +perft 6 1310683359 + +id 1 +epd nr1nkbqr/ppp3pp/5p2/3pp3/6b1/3PP3/PPP2PPP/NRBNKBQR w hb - 0 9 +perft 1 18 +perft 2 664 +perft 3 13306 +perft 4 483892 +perft 5 10658989 +perft 6 386307449 + +id 1 +epd nrbnk1rb/ppp1pq1p/3p4/5pp1/2P1P3/1N6/PP1PKPPP/1RBN1QRB w gb - 2 9 +perft 1 25 +perft 2 966 +perft 3 24026 +perft 4 920345 +perft 5 23957242 +perft 6 913710194 + +id 1 +epd 1brnbkqr/pppppp2/6p1/7p/1Pn5/P1NP4/2P1PPPP/NBR1BKQR w HChc - 0 9 +perft 1 22 +perft 2 627 +perft 3 13760 +perft 4 395829 +perft 5 9627826 +perft 6 285900573 + +id 1 +epd nrnbbk1r/p1pppppq/8/7p/1p6/P5PP/1PPPPPQ1/NRNBBK1R w HBhb - 2 9 +perft 1 29 +perft 2 888 +perft 3 26742 +perft 4 874270 +perft 5 27229468 +perft 6 930799376 + +id 1 +epd n1nkb1qr/prppppbp/6p1/1p6/2P2P2/P7/1P1PP1PP/NRNKBBQR w HBh - 1 9 +perft 1 29 +perft 2 804 +perft 3 24701 +perft 4 688520 +perft 5 21952444 +perft 6 623156747 + +id 1 +epd nr2bqrb/ppkpp1pp/1np5/5p1P/5P2/2P5/PP1PP1P1/NRNKBQRB w GB - 0 9 +perft 1 22 +perft 2 530 +perft 3 13055 +perft 4 347657 +perft 5 9244693 +perft 6 264088392 + +id 1 +epd nbr1kqbr/p3pppp/2ppn3/1p4P1/4P3/1P6/P1PP1P1P/NBRNKQBR w HChc - 1 9 +perft 1 23 +perft 2 555 +perft 3 14291 +perft 4 350917 +perft 5 9692630 +perft 6 247479180 + +id 1 +epd nr1bkqbr/1p1pp1pp/pnp2p2/8/6P1/P1PP4/1P2PP1P/NRNBKQBR w HBhb - 0 9 +perft 1 22 +perft 2 565 +perft 3 13343 +perft 4 365663 +perft 5 9305533 +perft 6 268612479 + +id 1 +epd nr1kqbbr/np2pppp/p1p5/1B1p1P2/8/4P3/PPPP2PP/NRNKQ1BR w HBhb - 0 9 +perft 1 32 +perft 2 730 +perft 3 23391 +perft 4 556995 +perft 5 18103280 +perft 6 454569900 + +id 1 +epd nrnk1rbb/p1p2ppp/3pq3/Qp2p3/1P1P4/8/P1P1PPPP/NRN1KRBB w fb - 2 9 +perft 1 28 +perft 2 873 +perft 3 25683 +perft 4 791823 +perft 5 23868737 +perft 6 747991356 + +id 1 +epd bbnrnkrq/pp1ppp1p/6p1/2p5/6P1/P5RP/1PPPPP2/BBNRNK1Q w Dgd - 3 9 +perft 1 37 +perft 2 1260 +perft 3 45060 +perft 4 1542086 +perft 5 54843403 +perft 6 1898432768 + +id 1 +epd bnrb1rkq/ppnpppp1/3Q4/2p4p/7P/N7/PPPPPPP1/B1RBNKR1 w GC - 2 9 +perft 1 38 +perft 2 878 +perft 3 31944 +perft 4 800440 +perft 5 28784300 +perft 6 784569826 + +id 1 +epd bnrnkbrq/p1ppppp1/1p5p/8/P2PP3/5P2/1PP3PP/BNRNKBRQ w GCgc - 1 9 +perft 1 26 +perft 2 617 +perft 3 16992 +perft 4 419099 +perft 5 11965544 +perft 6 311309576 + +id 1 +epd bnrnkrqb/pp2p2p/2pp1pp1/8/P7/2PP1P2/1P2P1PP/BNRNKRQB w FCfc - 0 9 +perft 1 26 +perft 2 721 +perft 3 19726 +perft 4 560824 +perft 5 15966934 +perft 6 467132503 + +id 1 +epd nbbrnkr1/1pppp1p1/p6q/P4p1p/8/5P2/1PPPP1PP/NBBRNRKQ w gd - 2 9 +perft 1 18 +perft 2 556 +perft 3 10484 +perft 4 316634 +perft 5 6629293 +perft 6 202528241 + +id 1 +epd nrb1nkrq/2pp1ppp/p4b2/1p2p3/P4B2/3P4/1PP1PPPP/NR1BNRKQ w gb - 0 9 +perft 1 24 +perft 2 562 +perft 3 14017 +perft 4 355433 +perft 5 9227883 +perft 6 247634489 + +id 1 +epd nrbnkbrq/p3p1pp/1p6/2pp1P2/8/3PP3/PPP2P1P/NRBNKBRQ w GBgb - 0 9 +perft 1 31 +perft 2 746 +perft 3 24819 +perft 4 608523 +perft 5 21019301 +perft 6 542954168 + +id 1 +epd nrbnkrqb/pppp1p1p/4p1p1/8/7P/2P1P3/PPNP1PP1/1RBNKRQB w FBfb - 0 9 +perft 1 20 +perft 2 459 +perft 3 9998 +perft 4 242762 +perft 5 5760165 +perft 6 146614723 + +id 1 +epd nbrn1krq/ppp1p2p/6b1/3p1pp1/8/4N1PP/PPPPPP2/NBR1BRKQ w gc - 1 9 +perft 1 27 +perft 2 835 +perft 3 23632 +perft 4 766397 +perft 5 22667987 +perft 6 760795567 + +id 1 +epd nrnbbkrq/p1pp2pp/5p2/1p6/2P1pP1B/1P6/P2PP1PP/NRNB1KRQ w GBgb - 0 9 +perft 1 24 +perft 2 646 +perft 3 16102 +perft 4 444472 +perft 5 11489727 +perft 6 324948755 + +id 1 +epd nrn1bbrq/1ppkppp1/p2p3p/8/1P3N2/4P3/P1PP1PPP/NR1KBBRQ w GB - 2 9 +perft 1 32 +perft 2 591 +perft 3 18722 +perft 4 381683 +perft 5 12069159 +perft 6 269922838 + +id 1 +epd n1krbrqb/1ppppppp/p7/8/4n3/P4P1P/1PPPPQP1/NRNKBR1B w FB - 2 9 +perft 1 26 +perft 2 639 +perft 3 16988 +perft 4 417190 +perft 5 12167153 +perft 6 312633873 + +id 1 +epd n1rnkrbq/1p1ppp1p/8/p1p1b1p1/3PQ1P1/4N3/PPP1PP1P/NBR1KRB1 w FCfc - 0 9 +perft 1 35 +perft 2 1027 +perft 3 35731 +perft 4 1040417 +perft 5 35738410 +perft 6 1060661628 + +id 1 +epd nrnbkrbq/2pp1pp1/pp6/4p2p/P7/5PPP/1PPPP3/NRNBKRBQ w FBfb - 0 9 +perft 1 26 +perft 2 628 +perft 3 16731 +perft 4 436075 +perft 5 11920087 +perft 6 331498921 + +id 1 +epd 1rnkrbbq/pp1p2pp/1n3p2/1Bp1p3/1P6/1N2P3/P1PP1PPP/1RNKR1BQ w EBeb - 0 9 +perft 1 33 +perft 2 992 +perft 3 32244 +perft 4 983481 +perft 5 31703749 +perft 6 980306735 + +id 1 +epd nr1krqbb/p1ppppp1/8/1p5p/1Pn5/5P2/P1PPP1PP/NRNKRQBB w EBeb - 0 9 +perft 1 24 +perft 2 670 +perft 3 15985 +perft 4 445492 +perft 5 11371067 +perft 6 325556465 + +id 1 +epd bbq1rkr1/1ppppppp/p1n2n2/8/2P2P2/1P6/PQ1PP1PP/BB1NRKNR w HEe - 3 9 +perft 1 32 +perft 2 794 +perft 3 26846 +perft 4 689334 +perft 5 24085223 +perft 6 645633370 + +id 1 +epd b1nbrknr/1qppp1pp/p4p2/1p6/6P1/P2NP3/1PPP1P1P/BQ1BRKNR w HEhe - 1 9 +perft 1 25 +perft 2 663 +perft 3 17138 +perft 4 482994 +perft 5 13157826 +perft 6 389603029 + +id 1 +epd bqnrk1nr/pp2ppbp/6p1/2pp4/2P5/5P2/PPQPP1PP/B1NRKBNR w HDhd - 0 9 +perft 1 26 +perft 2 850 +perft 3 22876 +perft 4 759768 +perft 5 21341087 +perft 6 719712622 + +id 1 +epd bqnrknrb/1ppp1p1p/p7/6p1/1P2p3/P1PN4/3PPPPP/BQ1RKNRB w GDgd - 0 9 +perft 1 25 +perft 2 721 +perft 3 19290 +perft 4 581913 +perft 5 16391601 +perft 6 511725087 + +id 1 +epd q1b1rknr/pp1pppp1/4n2p/2p1b3/1PP5/4P3/PQ1P1PPP/1BBNRKNR w HEhe - 1 9 +perft 1 32 +perft 2 975 +perft 3 32566 +perft 4 955493 +perft 5 32649943 +perft 6 962536105 + +id 1 +epd qnbbrknr/1p1ppppp/8/p1p5/5P2/PP1P4/2P1P1PP/QNBBRKNR w HEhe - 0 9 +perft 1 27 +perft 2 573 +perft 3 16331 +perft 4 391656 +perft 5 11562434 +perft 6 301166330 + +id 1 +epd q1brkb1r/p1pppppp/np3B2/8/6n1/1P5N/P1PPPPPP/QN1RKB1R w HDhd - 0 9 +perft 1 32 +perft 2 984 +perft 3 31549 +perft 4 1007217 +perft 5 32597704 +perft 6 1075429389 + +id 1 +epd qn1rk1rb/p1pppppp/1p2n3/8/2b5/4NPP1/PPPPP1RP/QNBRK2B w Dgd - 4 9 +perft 1 22 +perft 2 802 +perft 3 19156 +perft 4 697722 +perft 5 17761431 +perft 6 650603534 + +id 1 +epd qbnrbknr/ppp2p1p/8/3pp1p1/1PP1B3/5N2/P2PPPPP/Q1NRBK1R w HDhd - 0 9 +perft 1 34 +perft 2 943 +perft 3 32506 +perft 4 930619 +perft 5 32523099 +perft 6 955802240 + +id 1 +epd qnrbb1nr/pp1p1ppp/2p2k2/4p3/4P3/5PPP/PPPP4/QNRBBKNR w HC - 0 9 +perft 1 20 +perft 2 460 +perft 3 10287 +perft 4 241640 +perft 5 5846781 +perft 6 140714047 + +id 1 +epd qnr1bbnr/ppk1p1pp/3p4/2p2p2/8/2P5/PP1PPPPP/QNKRBBNR w - - 1 9 +perft 1 19 +perft 2 572 +perft 3 11834 +perft 4 357340 +perft 5 7994547 +perft 6 243724815 + +id 1 +epd qnrkbnrb/1p1p1ppp/2p5/4p3/p7/N1BP4/PPP1PPPP/Q1R1KNRB w gc - 0 9 +perft 1 27 +perft 2 579 +perft 3 16233 +perft 4 375168 +perft 5 10845146 +perft 6 268229097 + +id 1 +epd qbnrkn1r/1pppp1p1/p3bp2/2BN3p/8/5P2/PPPPP1PP/QBNRK2R w HDhd - 0 9 +perft 1 40 +perft 2 1027 +perft 3 38728 +perft 4 1059229 +perft 5 38511307 +perft 6 1104094381 + +id 1 +epd qnrbknbr/1pp2ppp/4p3/p6N/2p5/8/PPPPPPPP/Q1RBK1BR w HChc - 0 9 +perft 1 22 +perft 2 510 +perft 3 11844 +perft 4 300180 +perft 5 7403327 +perft 6 200581103 + +id 1 +epd 1qkrnbbr/p1pppppp/2n5/1p6/8/5NP1/PPPPPP1P/QNRK1BBR w HC - 4 9 +perft 1 24 +perft 2 549 +perft 3 13987 +perft 4 352037 +perft 5 9396521 +perft 6 255676649 + +id 1 +epd q1rknr1b/1ppppppb/2n5/p2B3p/8/1PN3P1/P1PPPP1P/Q1RKNRB1 w FCfc - 3 9 +perft 1 31 +perft 2 924 +perft 3 28520 +perft 4 861944 +perft 5 27463479 +perft 6 847726572 + +id 1 +epd bbnqrk1r/pp1pppp1/2p4p/8/6n1/1N1P1P2/PPP1P1PP/BBQ1RKNR w HEhe - 4 9 +perft 1 24 +perft 2 804 +perft 3 20147 +perft 4 666341 +perft 5 18024195 +perft 6 595947631 + +id 1 +epd bn1brknr/ppp1p1pp/5p2/3p4/6qQ/3P3P/PPP1PPP1/BN1BRKNR w HEhe - 4 9 +perft 1 25 +perft 2 854 +perft 3 22991 +perft 4 704173 +perft 5 20290974 +perft 6 600195008 + +id 1 +epd 1nqrkbnr/2pp1ppp/pp2p3/3b4/2P5/N7/PP1PPPPP/B1QRKBNR w HDhd - 0 9 +perft 1 22 +perft 2 651 +perft 3 16173 +perft 4 479152 +perft 5 13133439 +perft 6 390886040 + +id 1 +epd bnqrk1rb/1pp1pppp/p2p4/4n3/2PPP3/8/PP3PPP/BNQRKNRB w GDgd - 1 9 +perft 1 30 +perft 2 950 +perft 3 28169 +perft 4 889687 +perft 5 27610213 +perft 6 880739164 + +id 1 +epd nbb1rknr/1ppq1ppp/3p4/p3p3/4P3/1N2R3/PPPP1PPP/1BBQ1KNR w Hhe - 2 9 +perft 1 33 +perft 2 988 +perft 3 31293 +perft 4 967575 +perft 5 30894863 +perft 6 985384035 + +id 1 +epd nqbbrknr/2ppp2p/pp4p1/5p2/7P/3P1P2/PPPBP1P1/NQ1BRKNR w HEhe - 0 9 +perft 1 27 +perft 2 492 +perft 3 13266 +perft 4 276569 +perft 5 7583292 +perft 6 175376176 + +id 1 +epd 1qbrkb1r/pppppppp/8/3n4/4P1n1/PN6/1PPP1P1P/1QBRKBNR w HDhd - 3 9 +perft 1 28 +perft 2 800 +perft 3 21982 +perft 4 630374 +perft 5 17313279 +perft 6 507140861 + +id 1 +epd 1qbrknrb/1p1ppppp/1np5/8/p4P1P/4P1N1/PPPP2P1/NQBRK1RB w GDgd - 0 9 +perft 1 21 +perft 2 482 +perft 3 10581 +perft 4 267935 +perft 5 6218644 +perft 6 168704845 + +id 1 +epd nbqrbkr1/ppp1pppp/8/3p4/6n1/2P2PPN/PP1PP2P/NBQRBK1R w HDd - 1 9 +perft 1 29 +perft 2 921 +perft 3 25748 +perft 4 840262 +perft 5 24138518 +perft 6 806554650 + +id 1 +epd nqrb1knr/1ppbpp1p/p7/3p2p1/2P3P1/5P1P/PP1PP3/NQRBBKNR w HChc - 1 9 +perft 1 31 +perft 2 803 +perft 3 25857 +perft 4 665799 +perft 5 21998733 +perft 6 583349773 + +id 1 +epd 1qrkbbr1/pppp1ppp/1n3n2/4p3/5P2/1N6/PPPPP1PP/1QRKBBNR w HCc - 0 9 +perft 1 25 +perft 2 715 +perft 3 19118 +perft 4 556325 +perft 5 15514933 +perft 6 459533767 + +id 1 +epd nqrkb1rb/pp2pppp/2p1n3/3p4/3PP1N1/8/PPP2PPP/NQRKB1RB w GCgc - 0 9 +perft 1 26 +perft 2 795 +perft 3 21752 +perft 4 679387 +perft 5 19185851 +perft 6 616508881 + +id 1 +epd nb1rknbr/pp2ppp1/8/2Bp3p/6P1/2P2P1q/PP1PP2P/NBQRKN1R w HDhd - 0 9 +perft 1 35 +perft 2 1391 +perft 3 43025 +perft 4 1726888 +perft 5 53033675 +perft 6 2139267832 + +id 1 +epd nqrbkn1r/pp1pp1pp/8/2p2p2/5P2/P3B2P/1PbPP1P1/NQRBKN1R w HChc - 0 9 +perft 1 23 +perft 2 758 +perft 3 19439 +perft 4 653854 +perft 5 18296195 +perft 6 628403401 + +id 1 +epd nqrknbbr/pp1pppp1/7p/2p5/7P/1P1N4/P1PPPPPB/NQRK1B1R w HChc - 2 9 +perft 1 29 +perft 2 824 +perft 3 23137 +perft 4 683686 +perft 5 19429491 +perft 6 595493802 + +id 1 +epd 1qrknrbb/B1p1pppp/8/1p1p4/2n2P2/1P6/P1PPP1PP/NQRKNR1B w FCfc - 0 9 +perft 1 28 +perft 2 771 +perft 3 20237 +perft 4 581721 +perft 5 16065378 +perft 6 483037840 + +id 1 +epd bbnrqk1r/1ppppppp/8/7n/1p6/P6P/1BPPPPP1/1BNRQKNR w HDhd - 0 9 +perft 1 25 +perft 2 601 +perft 3 15471 +perft 4 396661 +perft 5 10697065 +perft 6 289472497 + +id 1 +epd bnrbqknr/ppp3p1/3ppp1Q/7p/3P4/1P6/P1P1PPPP/BNRB1KNR w HChc - 0 9 +perft 1 32 +perft 2 845 +perft 3 26876 +perft 4 742888 +perft 5 23717883 +perft 6 682154649 + +id 1 +epd bn1qkb1r/pprppppp/8/2p5/2PPP1n1/8/PPR2PPP/BN1QKBNR w Hh - 1 9 +perft 1 32 +perft 2 856 +perft 3 27829 +perft 4 768595 +perft 5 25245957 +perft 6 727424329 + +id 1 +epd 1nrqknrb/p1pp1ppp/1p2p3/3N4/5P1P/5b2/PPPPP3/B1RQKNRB w GCgc - 2 9 +perft 1 33 +perft 2 873 +perft 3 27685 +perft 4 779473 +perft 5 25128076 +perft 6 745401024 + +id 1 +epd nbbrqrk1/pppppppp/8/2N1n3/P7/6P1/1PPPPP1P/1BBRQKNR w HD - 3 9 +perft 1 25 +perft 2 555 +perft 3 14339 +perft 4 342296 +perft 5 9153089 +perft 6 234841945 + +id 1 +epd 1rbbqknr/1ppp1pp1/1n2p3/p6p/4P1P1/P6N/1PPP1P1P/NRBBQK1R w HBhb - 0 9 +perft 1 25 +perft 2 693 +perft 3 18652 +perft 4 528070 +perft 5 15133381 +perft 6 439344945 + +id 1 +epd nrq1kbnr/p1pbpppp/3p4/1p6/6P1/1N3N2/PPPPPP1P/1RBQKB1R w HBhb - 4 9 +perft 1 24 +perft 2 648 +perft 3 16640 +perft 4 471192 +perft 5 12871967 +perft 6 380436777 + +id 1 +epd nr1qknr1/p1pppp1p/b5p1/1p6/8/P4PP1/1bPPP1RP/NRBQKN1B w Bgb - 0 9 +perft 1 18 +perft 2 533 +perft 3 11215 +perft 4 331243 +perft 5 7777833 +perft 6 234905172 + +id 1 +epd nbrqbknr/1ppp2pp/8/4pp2/p2PP1P1/7N/PPP2P1P/NBRQBK1R w HChc - 0 9 +perft 1 29 +perft 2 803 +perft 3 24416 +perft 4 706648 +perft 5 22305910 +perft 6 672322762 + +id 1 +epd nr1b1k1r/ppp1pppp/2bp1n2/6P1/2P3q1/5P2/PP1PP2P/NRQBBKNR w HBhb - 1 9 +perft 1 27 +perft 2 1199 +perft 3 30908 +perft 4 1296241 +perft 5 35121759 +perft 6 1418677099 + +id 1 +epd nrqkbbnr/2pppp1p/p7/1p6/2P1Pp2/8/PPNP2PP/1RQKBBNR w HBhb - 0 9 +perft 1 28 +perft 2 613 +perft 3 17874 +perft 4 432750 +perft 5 13097064 +perft 6 345294379 + +id 1 +epd 1rqkbnrb/pp1ppp1p/1n4p1/B1p5/3PP3/4N3/PPP2PPP/NRQK2RB w GBgb - 0 9 +perft 1 33 +perft 2 723 +perft 3 23991 +perft 4 590970 +perft 5 19715083 +perft 6 535650233 + +id 1 +epd nbrqkn1r/1pppp2p/5pp1/p2b4/5P2/P2PN3/1PP1P1PP/NBRQK1BR w HChc - 2 9 +perft 1 23 +perft 2 607 +perft 3 15482 +perft 4 400970 +perft 5 11026383 +perft 6 290708878 + +id 1 +epd nrqbknbr/pp1pppp1/8/2p4p/P3PP2/8/1PPP2PP/NRQBKNBR w HBhb - 1 9 +perft 1 26 +perft 2 700 +perft 3 19371 +perft 4 556026 +perft 5 16058815 +perft 6 485460242 + +id 1 +epd nrqknbbr/p2pppp1/1pp5/6Qp/3P4/1P3P2/P1P1P1PP/NR1KNBBR w HBhb - 0 9 +perft 1 40 +perft 2 905 +perft 3 32932 +perft 4 829746 +perft 5 29263502 +perft 6 791963709 + +id 1 +epd nrqknrbb/1p3ppp/p2p4/2p1p3/1P6/3PP1P1/P1P2P1P/NRQKNRBB w FBfb - 0 9 +perft 1 29 +perft 2 780 +perft 3 22643 +perft 4 654495 +perft 5 19532077 +perft 6 593181101 + +id 1 +epd 1bnrkqnr/p1pppp2/7p/1p4p1/4b3/7N/PPPP1PPP/BBNRKQ1R w HDhd - 0 9 +perft 1 25 +perft 2 725 +perft 3 19808 +perft 4 565006 +perft 5 16661676 +perft 6 487354613 + +id 1 +epd bnrbkq1r/pp2p1pp/5n2/2pp1p2/P7/N1PP4/1P2PPPP/B1RBKQNR w HChc - 1 9 +perft 1 24 +perft 2 745 +perft 3 18494 +perft 4 584015 +perft 5 15079602 +perft 6 488924040 + +id 1 +epd 2rkqbnr/p1pppppp/2b5/1pn5/1P3P1Q/2B5/P1PPP1PP/1NRK1BNR w HChc - 3 9 +perft 1 33 +perft 2 904 +perft 3 30111 +perft 4 840025 +perft 5 28194726 +perft 6 801757709 + +id 1 +epd bnrkqnrb/2pppp2/8/pp4pp/1P5P/6P1/P1PPPPB1/BNRKQNR1 w GCgc - 0 9 +perft 1 34 +perft 2 1059 +perft 3 34090 +perft 4 1054311 +perft 5 33195397 +perft 6 1036498304 + +id 1 +epd 1bbrkq1r/pppp2pp/1n2pp1n/8/2PP4/1N4P1/PP2PP1P/1BBRKQNR w HDhd - 1 9 +perft 1 33 +perft 2 891 +perft 3 28907 +perft 4 814247 +perft 5 26970098 +perft 6 788040469 + +id 1 +epd nrbbkqnr/1p2pp1p/p1p3p1/3p4/8/1PP5/P2PPPPP/NRBBKQNR w HBhb - 0 9 +perft 1 21 +perft 2 567 +perft 3 13212 +perft 4 376487 +perft 5 9539687 +perft 6 284426039 + +id 1 +epd 1rbkqbr1/ppp1pppp/1n5n/3p4/3P4/1PP3P1/P3PP1P/NRBKQBNR w HBb - 1 9 +perft 1 27 +perft 2 752 +perft 3 20686 +perft 4 606783 +perft 5 16986290 +perft 6 521817800 + +id 1 +epd nrbkq1rb/1ppp1pp1/4p1n1/p6p/2PP4/5P2/PPK1P1PP/NRB1QNRB w gb - 0 9 +perft 1 35 +perft 2 697 +perft 3 23678 +perft 4 505836 +perft 5 16906409 +perft 6 390324794 + +id 1 +epd nbrkbqnr/p2pp1p1/5p2/1pp4p/7P/3P2P1/PPP1PP2/NBKRBQNR w hc - 0 9 +perft 1 25 +perft 2 679 +perft 3 17223 +perft 4 484921 +perft 5 12879258 +perft 6 376652259 + +id 1 +epd nrkb1qnr/ppppp1p1/6bp/5p2/1PP1P1P1/8/P2P1P1P/NRKBBQNR w HBhb - 1 9 +perft 1 32 +perft 2 761 +perft 3 24586 +perft 4 632916 +perft 5 20671433 +perft 6 568524724 + +id 1 +epd nrk1bbnr/p1q1pppp/1ppp4/8/3P3P/4K3/PPP1PPP1/NR1QBBNR w hb - 0 9 +perft 1 30 +perft 2 719 +perft 3 21683 +perft 4 541389 +perft 5 16278120 +perft 6 423649784 + +id 1 +epd nrkqbr1b/1pppp1pp/5pn1/p6N/1P3P2/8/P1PPP1PP/NRKQB1RB w GBb - 0 9 +perft 1 26 +perft 2 494 +perft 3 13815 +perft 4 296170 +perft 5 8763742 +perft 6 206993496 + +id 1 +epd nbrkq2r/pppp1bpp/4p1n1/5p2/7P/2P3N1/PP1PPPP1/NBKRQ1BR w hc - 0 9 +perft 1 27 +perft 2 701 +perft 3 19536 +perft 4 535052 +perft 5 15394667 +perft 6 443506342 + +id 1 +epd nrkbqnbr/2ppp2p/pp6/5pp1/P1P5/8/1P1PPPPP/NRKBQNBR w HBhb - 0 9 +perft 1 21 +perft 2 487 +perft 3 11341 +perft 4 285387 +perft 5 7218486 +perft 6 193586674 + +id 1 +epd nr1qnbbr/pk1pppp1/1pp4p/8/3P4/5P1P/PPP1P1P1/NRKQNBBR w HB - 0 9 +perft 1 22 +perft 2 546 +perft 3 13615 +perft 4 352855 +perft 5 9587439 +perft 6 259830255 + +id 1 +epd nrkq1rbb/pp1ppp1p/2pn4/8/PP3Pp1/7P/2PPP1P1/NRKQNRBB w FBfb - 0 9 +perft 1 26 +perft 2 839 +perft 3 22075 +perft 4 723845 +perft 5 19867117 +perft 6 658535326 + +id 1 +epd b2rknqr/pp1ppppp/8/2P5/n7/P7/1PPNPPPb/BBNRK1QR w HDhd - 2 9 +perft 1 24 +perft 2 699 +perft 3 19523 +perft 4 575172 +perft 5 17734818 +perft 6 535094237 + +id 1 +epd bnrbknqr/pp2p2p/2p3p1/3p1p2/8/3P4/PPPNPPPP/B1RBKNQR w HChc - 0 9 +perft 1 23 +perft 2 580 +perft 3 14320 +perft 4 385917 +perft 5 10133092 +perft 6 288041554 + +id 1 +epd bnrknb1r/pppp2pp/8/4pp2/6P1/3P3P/qPP1PPQ1/BNRKNB1R w HChc - 0 9 +perft 1 28 +perft 2 1100 +perft 3 31813 +perft 4 1217514 +perft 5 36142423 +perft 6 1361341249 + +id 1 +epd b1rknqrb/ppp1p1p1/2np1p1p/8/4N3/6PQ/PPPPPP1P/B1RKN1RB w GCgc - 0 9 +perft 1 36 +perft 2 629 +perft 3 23082 +perft 4 453064 +perft 5 16897544 +perft 6 367503974 + +id 1 +epd nb1rknqr/pbppp2p/6p1/1p3p2/5P2/3KP3/PPPP2PP/NBBR1NQR w hd - 2 9 +perft 1 18 +perft 2 557 +perft 3 9779 +perft 4 300744 +perft 5 5822387 +perft 6 180936551 + +id 1 +epd nr1bknqr/1ppb1ppp/p7/3pp3/B7/2P3NP/PP1PPPP1/NRB1K1QR w HBhb - 2 9 +perft 1 28 +perft 2 688 +perft 3 19541 +perft 4 519785 +perft 5 15153092 +perft 6 425149249 + +id 1 +epd nrbkn2r/pppp1pqp/4p1p1/8/3P2P1/P3B3/P1P1PP1P/NR1KNBQR w HBhb - 1 9 +perft 1 32 +perft 2 808 +perft 3 25578 +perft 4 676525 +perft 5 22094260 +perft 6 609377239 + +id 1 +epd nrbknqrb/2p1ppp1/1p6/p2p2Bp/1P6/3P1P2/P1P1P1PP/NR1KNQRB w GBgb - 0 9 +perft 1 30 +perft 2 625 +perft 3 18288 +perft 4 418895 +perft 5 12225742 +perft 6 301834282 + +id 1 +epd nbr1knqr/1pp1p1pp/3p1pb1/8/7P/5P2/PPPPPQP1/NBRKBN1R w HC - 2 9 +perft 1 29 +perft 2 863 +perft 3 25767 +perft 4 800239 +perft 5 24965592 +perft 6 799182442 + +id 1 +epd n1kbbnqr/prp2ppp/1p1p4/4p3/1P2P3/3P1B2/P1P2PPP/NRK1BNQR w HBh - 2 9 +perft 1 26 +perft 2 653 +perft 3 17020 +perft 4 449719 +perft 5 12187583 +perft 6 336872952 + +id 1 +epd nrknbbqr/pp3p1p/B3p1p1/2pp4/4P3/2N3P1/PPPP1P1P/NRK1B1QR w HBhb - 0 9 +perft 1 29 +perft 2 683 +perft 3 19755 +perft 4 501807 +perft 5 14684565 +perft 6 394951291 + +id 1 +epd n1knbqrb/pr1p1ppp/Qp6/2p1p3/4P3/6P1/PPPP1P1P/NRKNB1RB w GBg - 2 9 +perft 1 31 +perft 2 552 +perft 3 17197 +perft 4 371343 +perft 5 11663330 +perft 6 283583340 + +id 1 +epd nbrknqbr/p3p1pp/1p1p1p2/2p5/2Q1PP2/8/PPPP2PP/NBRKN1BR w HChc - 0 9 +perft 1 37 +perft 2 913 +perft 3 32470 +perft 4 825748 +perft 5 28899548 +perft 6 759875563 + +id 1 +epd nrkb1qbr/pp1pppp1/5n2/7p/2p5/1N1NPP2/PPPP2PP/1RKB1QBR w HBhb - 0 9 +perft 1 25 +perft 2 712 +perft 3 18813 +perft 4 543870 +perft 5 15045589 +perft 6 445074372 + +id 1 +epd nrk2bbr/pppqpppp/3p4/8/1P3nP1/3P4/P1P1PP1P/NRKNQBBR w HBhb - 1 9 +perft 1 24 +perft 2 814 +perft 3 19954 +perft 4 670162 +perft 5 17603960 +perft 6 592121050 + +id 1 +epd nrknqrbb/1p2ppp1/2pp4/Q6p/P2P3P/8/1PP1PPP1/NRKN1RBB w FBfb - 0 9 +perft 1 34 +perft 2 513 +perft 3 16111 +perft 4 303908 +perft 5 9569590 +perft 6 206509331 + +id 1 +epd bbnrk1rq/pp2p1pp/2ppn3/5p2/8/3NNP1P/PPPPP1P1/BB1RK1RQ w GDgd - 1 9 +perft 1 28 +perft 2 697 +perft 3 20141 +perft 4 517917 +perft 5 15301879 +perft 6 410843713 + +id 1 +epd bnrbknrq/ppppp2p/6p1/5p2/4QPP1/8/PPPPP2P/BNRBKNR1 w GCgc - 0 9 +perft 1 37 +perft 2 901 +perft 3 32612 +perft 4 877372 +perft 5 31385912 +perft 6 903831981 + +id 1 +epd bnkrnbrq/ppppp1p1/B6p/5p2/8/4P3/PPPP1PPP/BNKRN1RQ w - - 0 9 +perft 1 26 +perft 2 417 +perft 3 11124 +perft 4 217095 +perft 5 5980981 +perft 6 133080499 + +id 1 +epd bnrk1rqb/2pppp1p/3n4/pp4p1/3Q1P2/2N3P1/PPPPP2P/B1RKNR1B w FCfc - 0 9 +perft 1 49 +perft 2 1655 +perft 3 74590 +perft 4 2512003 +perft 5 107234294 +perft 6 3651608327 + +id 1 +epd nbbrk1rq/pp2pppp/2pp4/8/2P2n2/6N1/PP1PP1PP/NBBRKR1Q w Dgd - 0 9 +perft 1 28 +perft 2 960 +perft 3 26841 +perft 4 884237 +perft 5 26083252 +perft 6 846682836 + +id 1 +epd nrbb2rq/pppk1ppp/4p1n1/3p4/6P1/1BP5/PP1PPPQP/NRB1KNR1 w GB - 0 9 +perft 1 28 +perft 2 735 +perft 3 22048 +perft 4 593839 +perft 5 18588316 +perft 6 512048946 + +id 1 +epd nrbk1brq/p1ppppp1/7p/1p6/4P1nP/P7/1PPP1PP1/NRBKNBRQ w GBgb - 0 9 +perft 1 22 +perft 2 572 +perft 3 12739 +perft 4 351494 +perft 5 8525056 +perft 6 247615348 + +id 1 +epd nrbk1rqb/1pp2ppp/5n2/p2pp3/5B2/1N1P2P1/PPP1PP1P/1R1KNRQB w FBfb - 0 9 +perft 1 35 +perft 2 927 +perft 3 31559 +perft 4 849932 +perft 5 28465693 +perft 6 783048748 + +id 1 +epd nbrkb1rq/p1pp1ppp/4n3/4p3/Pp6/6N1/1PPPPPPP/NBRKBRQ1 w Cgc - 0 9 +perft 1 20 +perft 2 456 +perft 3 10271 +perft 4 247733 +perft 5 6124625 +perft 6 154766108 + +id 1 +epd nrkb1nrq/p2pp1pp/1pp2p2/7b/6PP/5P2/PPPPP2N/NRKBB1RQ w GBgb - 0 9 +perft 1 21 +perft 2 479 +perft 3 11152 +perft 4 264493 +perft 5 6696458 +perft 6 165253524 + +id 1 +epd nr1nbbr1/pppkpp1p/6p1/3p4/P6P/1P6/1RPPPPP1/N1KNBBRQ w G - 1 9 +perft 1 20 +perft 2 498 +perft 3 11304 +perft 4 288813 +perft 5 7197322 +perft 6 188021682 + +id 1 +epd nrknbrqb/3p1ppp/ppN1p3/8/6P1/8/PPPPPP1P/1RKNBRQB w FBfb - 0 9 +perft 1 32 +perft 2 526 +perft 3 17267 +perft 4 319836 +perft 5 10755190 +perft 6 220058991 + +id 1 +epd nbrkn1bq/p1pppr1p/1p6/5pp1/8/1N2PP2/PPPP2PP/1BKRNRBQ w c - 1 9 +perft 1 19 +perft 2 491 +perft 3 10090 +perft 4 277313 +perft 5 6230616 +perft 6 180748649 + +id 1 +epd nrkbnrbq/ppppppp1/8/8/7p/PP3P2/2PPPRPP/NRKBN1BQ w Bfb - 0 9 +perft 1 16 +perft 2 353 +perft 3 6189 +perft 4 156002 +perft 5 3008668 +perft 6 82706705 + +id 1 +epd nrknrbbq/p4ppp/2p1p3/1p1p4/1P2P3/2P5/P1NP1PPP/1RKNRBBQ w EBeb - 0 9 +perft 1 29 +perft 2 728 +perft 3 21915 +perft 4 587668 +perft 5 18231199 +perft 6 511686397 + +id 1 +epd nrknr1bb/pppp1p2/7p/2qPp1p1/8/1P5P/P1P1PPP1/NRKNRQBB w EBeb - 0 9 +perft 1 20 +perft 2 714 +perft 3 14336 +perft 4 500458 +perft 5 11132758 +perft 6 386064577 + +id 1 +epd bbqnrrkn/ppp2p1p/3pp1p1/8/1PP5/2Q5/P1BPPPPP/B2NRKRN w GE - 0 9 +perft 1 39 +perft 2 593 +perft 3 23446 +perft 4 424799 +perft 5 16764576 +perft 6 346185058 + +id 1 +epd bqn1rkrn/p1p2ppp/1p1p4/4p3/3PP2b/8/PPP2PPP/BQNBRKRN w GEge - 2 9 +perft 1 25 +perft 2 773 +perft 3 20042 +perft 4 616817 +perft 5 16632403 +perft 6 515838333 + +id 1 +epd bqnrkb1n/p1p1pprp/3p4/1p2P1p1/2PP4/8/PP3PPP/BQNRKBRN w GDd - 1 9 +perft 1 31 +perft 2 860 +perft 3 28102 +perft 4 810379 +perft 5 27233018 +perft 6 813751250 + +id 1 +epd bqr1krnb/ppppppp1/7p/3n4/1P4P1/P4N2/2PPPP1P/BQNRKR1B w FDf - 3 9 +perft 1 31 +perft 2 709 +perft 3 22936 +perft 4 559830 +perft 5 18608857 +perft 6 480498340 + +id 1 +epd qbbn1krn/pp3ppp/4r3/2ppp3/P1P4P/8/1P1PPPP1/QBBNRKRN w GEg - 1 9 +perft 1 26 +perft 2 775 +perft 3 21100 +perft 4 649673 +perft 5 18476807 +perft 6 582542257 + +id 1 +epd qnbbrkrn/1p1pp2p/p7/2p2pp1/8/4P2P/PPPP1PPK/QNBBRR1N w ge - 0 9 +perft 1 25 +perft 2 599 +perft 3 15139 +perft 4 389104 +perft 5 10260500 +perft 6 279222412 + +id 1 +epd qnbrkbrn/1ppp2p1/p3p2p/5p2/P4P2/1P6/2PPP1PP/QNBRKBRN w GDgd - 0 9 +perft 1 27 +perft 2 588 +perft 3 16735 +perft 4 394829 +perft 5 11640416 +perft 6 293541380 + +id 1 +epd 1nbrkrnb/p1pppp1p/1pq3p1/8/4P3/P1P4N/1P1P1PPP/QNBRKR1B w FDfd - 1 9 +perft 1 18 +perft 2 609 +perft 3 11789 +perft 4 406831 +perft 5 8604788 +perft 6 299491047 + +id 1 +epd qb1r1krn/pppp2pp/1n2ppb1/4P3/7P/8/PPPP1PP1/QBNRBKRN w GDgd - 0 9 +perft 1 20 +perft 2 578 +perft 3 12205 +perft 4 349453 +perft 5 7939483 +perft 6 229142178 + +id 1 +epd qnr1bkrn/p3pppp/1bpp4/1p6/2P2PP1/8/PP1PPN1P/QNRBBKR1 w GCgc - 0 9 +perft 1 30 +perft 2 865 +perft 3 26617 +perft 4 771705 +perft 5 24475596 +perft 6 719842237 + +id 1 +epd 1nkrbbrn/qppppppp/8/8/p2P4/1P5P/P1P1PPP1/QNKRBBRN w - - 0 9 +perft 1 27 +perft 2 672 +perft 3 18371 +perft 4 505278 +perft 5 14065717 +perft 6 410130412 + +id 1 +epd 1qrkbrnb/ppp1p1pp/n2p4/5p2/4N3/8/PPPPPPPP/Q1RKBRNB w Ffc - 2 9 +perft 1 25 +perft 2 718 +perft 3 18573 +perft 4 536771 +perft 5 14404324 +perft 6 424279467 + +id 1 +epd q1nrkrbn/pp1pppp1/2p4p/8/P7/5Pb1/BPPPPNPP/Q1NRKRB1 w FDfd - 0 9 +perft 1 22 +perft 2 558 +perft 3 12911 +perft 4 336042 +perft 5 8516966 +perft 6 228074630 + +id 1 +epd qnrbkrbn/1p1p1pp1/p1p5/4p2p/8/3P1P2/PPP1P1PP/QNRBKRBN w FCfc - 0 9 +perft 1 28 +perft 2 669 +perft 3 17713 +perft 4 440930 +perft 5 12055174 +perft 6 313276304 + +id 1 +epd qnrkr1bn/p1pp1ppp/8/1p2p3/3P1P2/bP4P1/P1P1P2P/QNRKRBBN w ECec - 1 9 +perft 1 23 +perft 2 845 +perft 3 20973 +perft 4 759778 +perft 5 19939053 +perft 6 718075943 + +id 1 +epd q1krrnbb/p1p1pppp/2np4/1pB5/5P2/8/PPPPP1PP/QNRKRN1B w EC - 0 9 +perft 1 29 +perft 2 776 +perft 3 21966 +perft 4 631941 +perft 5 18110831 +perft 6 549019739 + +id 1 +epd bbn1rkrn/pp1p1ppp/8/2p1p1q1/6P1/P7/BPPPPP1P/B1NQRKRN w GEge - 0 9 +perft 1 26 +perft 2 936 +perft 3 25177 +perft 4 906801 +perft 5 24984621 +perft 6 901444251 + +id 1 +epd bn1brkrn/pp1qpp1p/2p3p1/3p4/1PPP4/P7/4PPPP/BNQBRKRN w GEge - 1 9 +perft 1 29 +perft 2 755 +perft 3 22858 +perft 4 645963 +perft 5 20128587 +perft 6 600207069 + +id 1 +epd b2rkbrn/p1pppppp/qp6/8/1n6/2B2P2/P1PPP1PP/1NQRKBRN w GDgd - 0 9 +perft 1 24 +perft 2 878 +perft 3 21440 +perft 4 791007 +perft 5 20840078 +perft 6 775795187 + +id 1 +epd b2rkrnb/pqp1pppp/n7/1p1p4/P7/N1P2N2/1P1PPPPP/B1QRKR1B w FDfd - 4 9 +perft 1 26 +perft 2 724 +perft 3 19558 +perft 4 571891 +perft 5 16109522 +perft 6 492933398 + +id 1 +epd 1bbqrkrn/ppppp1p1/8/5p1p/P1n3P1/3P4/1PP1PP1P/NBBQRRKN w ge - 1 9 +perft 1 25 +perft 2 678 +perft 3 17351 +perft 4 461211 +perft 5 12173245 +perft 6 329661421 + +id 1 +epd nqb1rrkn/ppp1bppp/3pp3/8/3P4/1P6/PQP1PPPP/N1BBRRKN w - - 1 9 +perft 1 23 +perft 2 503 +perft 3 12465 +perft 4 290341 +perft 5 7626054 +perft 6 188215608 + +id 1 +epd nqbrkbr1/p1pppppp/1p6/2N2n2/2P5/5P2/PP1PP1PP/1QBRKBRN w GDgd - 1 9 +perft 1 29 +perft 2 688 +perft 3 20289 +perft 4 506302 +perft 5 15167248 +perft 6 399015237 + +id 1 +epd nqbrkrn1/1ppppp2/6pp/p7/1P6/2Q5/P1PPPPPP/N1BRKRNB w FDfd - 0 9 +perft 1 36 +perft 2 602 +perft 3 20985 +perft 4 397340 +perft 5 13706856 +perft 6 291708797 + +id 1 +epd nbqrbrkn/pp1p1pp1/2p5/4p2p/2P3P1/1P3P2/P2PP2P/NBQRBKRN w GD - 0 9 +perft 1 34 +perft 2 655 +perft 3 22581 +perft 4 474396 +perft 5 16613630 +perft 6 379344541 + +id 1 +epd nqrbbrkn/1p1pppp1/8/p1p4p/4P2P/1N4P1/PPPP1P2/1QRBBKRN w GC - 0 9 +perft 1 23 +perft 2 597 +perft 3 14468 +perft 4 400357 +perft 5 10096863 +perft 6 294900903 + +id 1 +epd nqrkbbrn/2p1p1pp/pp1p1p2/8/P2N4/2P5/1P1PPPPP/1QRKBBRN w GCgc - 0 9 +perft 1 32 +perft 2 744 +perft 3 23310 +perft 4 550728 +perft 5 17597164 +perft 6 428786656 + +id 1 +epd n1krbrnb/q1pppppp/p7/1p6/3Q4/2P2P2/PP1PP1PP/N1RKBRNB w FC - 1 9 +perft 1 43 +perft 2 1038 +perft 3 41327 +perft 4 1074450 +perft 5 40918952 +perft 6 1126603824 + +id 1 +epd nb1rkrbn/p1pp1p1p/qp6/4p1p1/5PP1/P7/1PPPPB1P/NBQRKR1N w FDfd - 2 9 +perft 1 26 +perft 2 645 +perft 3 16463 +perft 4 445464 +perft 5 11911314 +perft 6 342563372 + +id 1 +epd nqr1krbn/pppp1ppp/8/8/3pP3/5P2/PPPb1NPP/NQRBKRB1 w FCfc - 3 9 +perft 1 2 +perft 2 51 +perft 3 1047 +perft 4 27743 +perft 5 612305 +perft 6 17040200 + +id 1 +epd n1rkrbbn/pqppppp1/7p/1p6/8/1NPP4/PP1KPPPP/1QR1RBBN w ec - 0 9 +perft 1 25 +perft 2 674 +perft 3 17553 +perft 4 505337 +perft 5 13421727 +perft 6 403551903 + +id 1 +epd 1qrkrnbb/1p1p1ppp/pnp1p3/8/3PP3/P6P/1PP2PP1/NQRKRNBB w ECec - 0 9 +perft 1 24 +perft 2 688 +perft 3 17342 +perft 4 511444 +perft 5 13322502 +perft 6 403441498 + +id 1 +epd 1bnrqkrn/2ppppp1/p7/1p1b3p/3PP1P1/8/PPPQ1P1P/BBNR1KRN w GDgd - 1 9 +perft 1 35 +perft 2 925 +perft 3 32238 +perft 4 857060 +perft 5 30458921 +perft 6 824344087 + +id 1 +epd bnrbqkr1/ppp2pp1/6n1/3pp2p/1P6/2N3N1/P1PPPPPP/B1RBQRK1 w gc - 0 9 +perft 1 23 +perft 2 704 +perft 3 17345 +perft 4 539587 +perft 5 14154852 +perft 6 450893738 + +id 1 +epd 1nrqkbrn/p1pppppp/8/1p1b4/P6P/5P2/1PPPP1P1/BNRQKBRN w GCgc - 1 9 +perft 1 19 +perft 2 505 +perft 3 10619 +perft 4 281422 +perft 5 6450025 +perft 6 175593967 + +id 1 +epd b1rqkrnb/ppppppp1/8/6p1/3n4/NP6/P1PPPP1P/B1RQKRNB w FCfc - 0 9 +perft 1 25 +perft 2 614 +perft 3 15578 +perft 4 377660 +perft 5 10391021 +perft 6 259629603 + +id 1 +epd nbbrqkrn/ppp3p1/3pp3/5p1p/1P2P3/P7/2PPQPPP/NBBR1KRN w GDgd - 0 9 +perft 1 30 +perft 2 833 +perft 3 25719 +perft 4 717713 +perft 5 22873901 +perft 6 649556666 + +id 1 +epd nr1bqrk1/ppp1pppp/6n1/3pP3/8/5PQb/PPPP2PP/NRBB1KRN w GB - 3 9 +perft 1 26 +perft 2 734 +perft 3 20161 +perft 4 582591 +perft 5 17199594 +perft 6 512134836 + +id 1 +epd 1rbqkbr1/ppppp1pp/1n6/4np2/3P1P2/6P1/PPPQP2P/NRB1KBRN w GBgb - 1 9 +perft 1 27 +perft 2 662 +perft 3 17897 +perft 4 447464 +perft 5 13038519 +perft 6 338365642 + +id 1 +epd nr1qkr1b/ppp1pp1p/4bn2/3p2p1/4P3/1Q6/PPPP1PPP/NRB1KRNB w FBfb - 4 9 +perft 1 33 +perft 2 939 +perft 3 30923 +perft 4 942138 +perft 5 30995969 +perft 6 991509814 + +id 1 +epd nb1qbkrn/pprp1pp1/7p/2p1pB2/Q1PP4/8/PP2PPPP/N1R1BKRN w GCg - 2 9 +perft 1 47 +perft 2 1128 +perft 3 50723 +perft 4 1306753 +perft 5 56747878 +perft 6 1560584212 + +id 1 +epd nrqb1rkn/pp2pppp/2bp4/2p5/6P1/2P3N1/PP1PPP1P/NRQBBRK1 w - - 3 9 +perft 1 24 +perft 2 828 +perft 3 21148 +perft 4 723705 +perft 5 19506135 +perft 6 668969549 + +id 1 +epd nrq1bbrn/ppkpp2p/2p3p1/P4p2/8/4P1N1/1PPP1PPP/NRQKBBR1 w GB - 0 9 +perft 1 25 +perft 2 525 +perft 3 13533 +perft 4 309994 +perft 5 8250997 +perft 6 201795680 + +id 1 +epd Br1kbrn1/pqpppp2/8/6pp/3b2P1/1N6/PPPPPP1P/1RQKBRN1 w FBfb - 3 9 +perft 1 20 +perft 2 790 +perft 3 18175 +perft 4 695905 +perft 5 17735648 +perft 6 669854148 + +id 1 +epd nbrqkrbn/2p1p1pp/p7/1p1p1p2/4P1P1/5P2/PPPP3P/NBRQKRBN w FCfc - 0 9 +perft 1 29 +perft 2 771 +perft 3 22489 +perft 4 647106 +perft 5 19192982 +perft 6 591335970 + +id 1 +epd 1rqbkrbn/1ppppp1p/1n6/p1N3p1/8/2P4P/PP1PPPP1/1RQBKRBN w FBfb - 0 9 +perft 1 29 +perft 2 502 +perft 3 14569 +perft 4 287739 +perft 5 8652810 +perft 6 191762235 + +id 1 +epd 1rqkrbbn/ppnpp1pp/8/2p5/6p1/3P4/PPP1PPPP/NRK1RBBN w eb - 0 9 +perft 1 19 +perft 2 531 +perft 3 10812 +perft 4 300384 +perft 5 6506674 +perft 6 184309316 + +id 1 +epd nrqkrnbb/p1pp2pp/5p2/4P3/2p5/4N3/PP1PP1PP/NRQKR1BB w EBeb - 0 9 +perft 1 26 +perft 2 800 +perft 3 23256 +perft 4 756695 +perft 5 23952941 +perft 6 809841274 + +id 1 +epd bbnrkqrn/pp3pp1/4p2p/2pp4/4P1P1/1PB5/P1PP1P1P/1BNRKQRN w GDgd - 0 9 +perft 1 33 +perft 2 915 +perft 3 30536 +perft 4 878648 +perft 5 29602610 +perft 6 881898159 + +id 1 +epd bnrbkqr1/1p2pppp/6n1/p1pp4/7P/P3P3/1PPPKPP1/BNRB1QRN w gc - 0 9 +perft 1 19 +perft 2 457 +perft 3 9332 +perft 4 238944 +perft 5 5356253 +perft 6 144653627 + +id 1 +epd b1rkqbrn/pp1p2pp/2n1p3/2p2p2/3P2PP/8/PPP1PP2/BNKRQBRN w gc - 0 9 +perft 1 30 +perft 2 985 +perft 3 30831 +perft 4 1011700 +perft 5 32684185 +perft 6 1080607773 + +id 1 +epd b1rkqrnb/2ppppp1/np6/p6p/1P6/P2P3P/2P1PPP1/BNRKQRNB w FCfc - 0 9 +perft 1 26 +perft 2 692 +perft 3 18732 +perft 4 517703 +perft 5 14561181 +perft 6 413226841 + +id 1 +epd nbbrkqrn/1ppp1p2/p6p/4p1p1/5P2/1P5P/P1PPPNP1/NBBRKQR1 w GDgd - 0 9 +perft 1 22 +perft 2 561 +perft 3 13222 +perft 4 367487 +perft 5 9307003 +perft 6 273928315 + +id 1 +epd nrbbkqrn/p1pppppp/8/1p6/4P3/7Q/PPPP1PPP/NRBBK1RN w GBgb - 0 9 +perft 1 38 +perft 2 769 +perft 3 28418 +perft 4 632310 +perft 5 23091070 +perft 6 560139600 + +id 1 +epd nrbkqbrn/1pppp2p/8/p4pp1/P4PQ1/8/1PPPP1PP/NRBK1BRN w GBgb - 0 9 +perft 1 23 +perft 2 507 +perft 3 13067 +perft 4 321423 +perft 5 8887567 +perft 6 237475184 + +id 1 +epd nr1kqr1b/pp2pppp/5n2/2pp4/P5b1/5P2/1PPPPRPP/NRBK1QNB w Bfb - 2 9 +perft 1 18 +perft 2 626 +perft 3 12386 +perft 4 434138 +perft 5 9465555 +perft 6 335004239 + +id 1 +epd nbkrbqrn/1pppppp1/8/4P2p/pP6/P7/2PP1PPP/NBRKBQRN w GC - 0 9 +perft 1 22 +perft 2 329 +perft 3 8475 +perft 4 148351 +perft 5 4160034 +perft 6 82875306 + +id 1 +epd nrkb1qrn/pp1pp1pp/8/5p1b/P1p4P/6N1/1PPPPPP1/NRKBBQR1 w GBgb - 2 9 +perft 1 16 +perft 2 479 +perft 3 9037 +perft 4 275354 +perft 5 5862341 +perft 6 184959796 + +id 1 +epd 1rkq1brn/ppppp1pp/1n6/3b1p2/3N3P/5P2/PPPPP1P1/1RKQBBRN w GBgb - 3 9 +perft 1 23 +perft 2 614 +perft 3 15324 +perft 4 418395 +perft 5 11090645 +perft 6 313526088 + +id 1 +epd nrk1brnb/pp1ppppp/2p5/3q4/5P2/PP6/1KPPP1PP/NR1QBRNB w fb - 1 9 +perft 1 25 +perft 2 942 +perft 3 21765 +perft 4 792179 +perft 5 19318837 +perft 6 685549171 + +id 1 +epd nbrkqr1n/1pppp2p/p4pp1/2Bb4/5P2/6P1/PPPPP2P/NBRKQ1RN w Cfc - 2 9 +perft 1 30 +perft 2 841 +perft 3 24775 +perft 4 677876 +perft 5 20145765 +perft 6 557578726 + +id 1 +epd n1kbqrbn/2p1pppp/1r6/pp1p4/P7/3P4/1PP1PPPP/NRKBQRBN w FBf - 2 9 +perft 1 21 +perft 2 591 +perft 3 14101 +perft 4 394289 +perft 5 10295086 +perft 6 292131422 + +id 1 +epd nrkqrbb1/ppp1pppp/3p4/8/4P3/2Pn1P2/PP4PP/NRKQRBBN w EBeb - 0 9 +perft 1 4 +perft 2 88 +perft 3 3090 +perft 4 73414 +perft 5 2640555 +perft 6 66958031 + +id 1 +epd nrkqrnbb/ppppp1p1/7p/1P3p2/3P4/2P5/P3PPPP/NRKQRNBB w EBeb - 0 9 +perft 1 29 +perft 2 689 +perft 3 21091 +perft 4 508789 +perft 5 16226660 +perft 6 408570219 + +id 1 +epd bbnr1rqn/pp2pkpp/2pp1p2/8/4P1P1/8/PPPP1P1P/BBNRKRQN w FD - 0 9 +perft 1 21 +perft 2 463 +perft 3 11135 +perft 4 256244 +perft 5 6826249 +perft 6 165025370 + +id 1 +epd bnrbk1qn/1pppprpp/8/p4p1P/6P1/3P4/PPP1PP2/BNRBKRQN w FCc - 0 9 +perft 1 22 +perft 2 459 +perft 3 11447 +perft 4 268157 +perft 5 7371098 +perft 6 190583454 + +id 1 +epd 1nrkrbqn/p1pp1ppp/4p3/1p6/1PP5/6PB/P2PPPbP/BNRKR1QN w ECec - 0 9 +perft 1 30 +perft 2 931 +perft 3 29012 +perft 4 887414 +perft 5 28412902 +perft 6 869228014 + +id 1 +epd b1rkr1nb/pppppqp1/n4B2/7p/8/1P4P1/P1PPPP1P/1NKRRQNB w ec - 1 9 +perft 1 36 +perft 2 934 +perft 3 31790 +perft 4 930926 +perft 5 30392925 +perft 6 952871799 + +id 1 +epd nbbrkrqn/p1ppp1p1/8/1p3p1p/2P3PP/8/PP1PPPQ1/NBBRKR1N w FDfd - 0 9 +perft 1 34 +perft 2 938 +perft 3 31848 +perft 4 921716 +perft 5 31185844 +perft 6 944483246 + +id 1 +epd 1rbbkrqn/ppp1pp2/1n1p2p1/7p/P3P1P1/3P4/1PP2P1P/NRBBKRQN w FBfb - 0 9 +perft 1 26 +perft 2 646 +perft 3 18083 +perft 4 472744 +perft 5 14006203 +perft 6 384101783 + +id 1 +epd nrbkrbq1/Qpppp1pp/2n5/5p2/P4P2/6N1/1PPPP1PP/NRBKRB2 w EBeb - 1 9 +perft 1 27 +perft 2 619 +perft 3 16713 +perft 4 421845 +perft 5 11718463 +perft 6 313794027 + +id 1 +epd 1rbkr1nb/pppp1qpp/1n6/4pp2/1PP1P3/8/PB1P1PPP/NR1KRQNB w EBeb - 1 9 +perft 1 32 +perft 2 1029 +perft 3 32970 +perft 4 1080977 +perft 5 35483796 +perft 6 1181835398 + +id 1 +epd nbrk1rqn/p1ppp2p/1p6/5ppb/8/1N2P2P/PPPP1PP1/1BKRBRQN w fc - 0 9 +perft 1 18 +perft 2 594 +perft 3 12350 +perft 4 408544 +perft 5 9329122 +perft 6 315021712 + +id 1 +epd nrkbbrqn/3pppp1/7p/ppp5/P7/1N5P/1PPPPPP1/1RKBBRQN w FBfb - 0 9 +perft 1 19 +perft 2 417 +perft 3 9026 +perft 4 218513 +perft 5 5236331 +perft 6 137024458 + +id 1 +epd nrkr1bqn/ppp1pppp/3p4/1b6/7P/P7/1PPPPPP1/NRKRBBQN w DBdb - 1 9 +perft 1 17 +perft 2 457 +perft 3 9083 +perft 4 243872 +perft 5 5503579 +perft 6 150091997 + +id 1 +epd nrkrbqnb/p4ppp/1p2p3/2pp4/6P1/2P2N2/PPNPPP1P/1RKRBQ1B w DBdb - 0 9 +perft 1 27 +perft 2 755 +perft 3 21012 +perft 4 620093 +perft 5 17883987 +perft 6 547233320 + +id 1 +epd nbkrr1bn/ppB2ppp/4p3/2qp4/4P3/5P2/PPPP2PP/NBRKRQ1N w EC - 1 9 +perft 1 37 +perft 2 1473 +perft 3 51939 +perft 4 1956521 +perft 5 68070015 +perft 6 2490912491 + +id 1 +epd n1kbrqbn/p1pp1pp1/4p2p/2B5/1r3P2/8/PPPPP1PP/NRKBRQ1N w EBe - 2 9 +perft 1 30 +perft 2 1029 +perft 3 30874 +perft 4 1053163 +perft 5 32318550 +perft 6 1106487743 + +id 1 +epd nrkrqbbn/2pppp1p/8/pp6/1P1P2p1/P5P1/2P1PP1P/NRKRQBBN w DBdb - 0 9 +perft 1 22 +perft 2 421 +perft 3 10034 +perft 4 221927 +perft 5 5754555 +perft 6 141245633 + +id 1 +epd nrkr1nbb/1ppp2pp/p3q3/4pp2/2P5/P3P3/1PKP1PPP/NR1RQNBB w db - 0 9 +perft 1 22 +perft 2 619 +perft 3 13953 +perft 4 411392 +perft 5 9905109 +perft 6 301403003 + +id 1 +epd bbnrkrnq/1pp1p2p/6p1/p2p1p2/8/1P2P3/P1PP1PPP/BBNRKRNQ w FDfd - 0 9 +perft 1 27 +perft 2 805 +perft 3 21915 +perft 4 688224 +perft 5 19133881 +perft 6 620749189 + +id 1 +epd bnrbkrn1/pp1ppp2/2p3pp/8/2Pq4/P4PP1/1P1PP2P/BNRBKRNQ w FCfc - 1 9 +perft 1 20 +perft 2 770 +perft 3 16593 +perft 4 577980 +perft 5 13581691 +perft 6 456736500 + +id 1 +epd b1rkrbnq/1pp1pppp/2np4/p5N1/8/1P2P3/P1PP1PPP/BNRKRB1Q w ECec - 0 9 +perft 1 37 +perft 2 740 +perft 3 27073 +perft 4 581744 +perft 5 21156664 +perft 6 485803600 + +id 1 +epd b1krrnqb/pp1ppp1p/n1p3p1/2N5/6P1/8/PPPPPP1P/B1RKRNQB w EC - 0 9 +perft 1 34 +perft 2 850 +perft 3 28494 +perft 4 752350 +perft 5 25360295 +perft 6 698159474 + +id 1 +epd 1bbr1rnq/ppppkppp/8/3np3/4P3/3P4/PPP1KPPP/NBBRR1NQ w - - 1 9 +perft 1 27 +perft 2 704 +perft 3 18290 +perft 4 480474 +perft 5 12817011 +perft 6 341026662 + +id 1 +epd nrbbk1nq/p1p1prpp/1p6/N2p1p2/P7/8/1PPPPPPP/R1BBKRNQ w Fb - 2 9 +perft 1 23 +perft 2 552 +perft 3 13710 +perft 4 348593 +perft 5 9236564 +perft 6 248469879 + +id 1 +epd 1rbkrb1q/1pppp1pp/1n5n/p4p2/P3P3/1P6/2PPNPPP/NRBKRB1Q w EBeb - 1 9 +perft 1 22 +perft 2 415 +perft 3 10198 +perft 4 217224 +perft 5 5735644 +perft 6 135295774 + +id 1 +epd nrbkr1qb/1pp1pppp/6n1/p2p4/2P1P3/1N4N1/PP1P1PPP/1RBKR1QB w EBeb - 0 9 +perft 1 27 +perft 2 709 +perft 3 19126 +perft 4 506214 +perft 5 14192779 +perft 6 380516508 + +id 1 +epd nbrkbrnq/p3p1pp/1pp2p2/3p4/1PP5/4P3/P1KP1PPP/NBR1BRNQ w fc - 0 9 +perft 1 24 +perft 2 715 +perft 3 18009 +perft 4 535054 +perft 5 14322279 +perft 6 427269976 + +id 1 +epd nrk1brnq/pp1p1pp1/7p/b1p1p3/1P6/6P1/P1PPPPQP/NRKBBRN1 w FBfb - 2 9 +perft 1 29 +perft 2 675 +perft 3 20352 +perft 4 492124 +perft 5 15316285 +perft 6 389051744 + +id 1 +epd nrkr1bnq/1p2pppp/p2p4/1bp5/PP6/1R5N/2PPPPPP/N1KRBB1Q w Ddb - 2 9 +perft 1 27 +perft 2 744 +perft 3 20494 +perft 4 571209 +perft 5 16188945 +perft 6 458900901 + +id 1 +epd nrk1b1qb/pppn1ppp/3rp3/3p4/2P3P1/3P4/PPN1PP1P/1RKRBNQB w DBb - 3 9 +perft 1 35 +perft 2 941 +perft 3 33203 +perft 4 935791 +perft 5 33150360 +perft 6 968024386 + +id 1 +epd nb1rrnbq/ppkp1ppp/8/2p1p3/P7/1N2P3/1PPP1PPP/1BKRRNBQ w - - 1 9 +perft 1 19 +perft 2 451 +perft 3 9655 +perft 4 235472 +perft 5 5506897 +perft 6 139436165 + +id 1 +epd nrkbrnbq/4pppp/1ppp4/p7/2P1P3/3P2N1/PP3PPP/NRKBR1BQ w EBeb - 0 9 +perft 1 29 +perft 2 591 +perft 3 17132 +perft 4 384358 +perft 5 11245508 +perft 6 270967202 + +id 1 +epd nrkrnbbq/3p1ppp/1p6/p1p1p3/3P2P1/P4Q2/1PP1PP1P/NRKRNBB1 w DBdb - 0 9 +perft 1 38 +perft 2 792 +perft 3 28597 +perft 4 640961 +perft 5 22654797 +perft 6 540864616 + +id 1 +epd nr1rnqbb/ppp1pp1p/3k2p1/3p4/1P5P/3P1N2/P1P1PPP1/NRKR1QBB w DB - 1 9 +perft 1 25 +perft 2 758 +perft 3 18547 +perft 4 543643 +perft 5 13890077 +perft 6 402109399 + +id 1 +epd bbqrnnkr/1ppp1p1p/5p2/p5p1/P7/1P4P1/2PPPP1P/1BQRNNKR w HDhd - 0 9 +perft 1 20 +perft 2 322 +perft 3 7224 +perft 4 145818 +perft 5 3588435 +perft 6 82754650 + +id 1 +epd bqrb2k1/pppppppr/5nnp/8/3P1P2/4P1N1/PPP3PP/BQRBN1KR w HCc - 1 9 +perft 1 25 +perft 2 597 +perft 3 15872 +perft 4 397970 +perft 5 11162476 +perft 6 295682250 + +id 1 +epd bqrnn1kr/1pppbppp/8/4p3/1p6/2P1N2P/P2PPPP1/BQR1NBKR w HChc - 1 9 +perft 1 34 +perft 2 921 +perft 3 31695 +perft 4 864023 +perft 5 30126510 +perft 6 850296236 + +id 1 +epd bqr1nkr1/pppppp2/2n3p1/7p/1P1b1P2/8/PQP1P1PP/B1RNNKRB w GCgc - 0 9 +perft 1 23 +perft 2 788 +perft 3 21539 +perft 4 686795 +perft 5 20849374 +perft 6 645694580 + +id 1 +epd qbbrnn1r/1pppp1pk/p7/5p1p/P2P3P/3N4/1PP1PPP1/QBBR1NKR w HD - 0 9 +perft 1 34 +perft 2 713 +perft 3 24475 +perft 4 562189 +perft 5 19494094 +perft 6 482645160 + +id 1 +epd qrbb2kr/p1pppppp/1p1n4/8/1P3n2/P7/Q1PPP1PP/1RBBNNKR w HBhb - 0 9 +perft 1 28 +perft 2 977 +perft 3 26955 +perft 4 949925 +perft 5 27802999 +perft 6 992109168 + +id 1 +epd qrb2bkr/1pp1pppp/2np1n2/pN6/3P4/4B3/PPP1PPPP/QR2NBKR w HBhb - 0 9 +perft 1 27 +perft 2 730 +perft 3 20534 +perft 4 585091 +perft 5 17005916 +perft 6 507008968 + +id 1 +epd qrbnnkrb/pp2pp1p/8/2pp2p1/7P/P1P5/QP1PPPP1/1RBNNKRB w GBgb - 0 9 +perft 1 24 +perft 2 813 +perft 3 21142 +perft 4 707925 +perft 5 19615756 +perft 6 655850285 + +id 1 +epd 1brnb1kr/p1pppppp/1p6/8/4q2n/1P2P1P1/PNPP1P1P/QBR1BNKR w HChc - 3 9 +perft 1 17 +perft 2 734 +perft 3 13462 +perft 4 530809 +perft 5 11032633 +perft 6 416356876 + +id 1 +epd 1rnbbnkr/1pp1pppp/1q1p4/p7/4P3/5PN1/PPPP1BPP/QRNB2KR w HBhb - 1 9 +perft 1 26 +perft 2 809 +perft 3 21764 +perft 4 706677 +perft 5 20292750 +perft 6 675408811 + +id 1 +epd qrnnbb1Q/ppp1pk1p/3p2p1/5p2/PP6/5P2/2PPP1PP/1RNNBBKR w HB - 0 9 +perft 1 37 +perft 2 751 +perft 3 27902 +perft 4 603931 +perft 5 22443036 +perft 6 515122176 + +id 1 +epd qrnnbkrb/p3p1pp/3p1p2/1pp5/PP2P3/8/2PP1PPP/QRNNBRKB w gb - 0 9 +perft 1 30 +perft 2 906 +perft 3 27955 +perft 4 872526 +perft 5 27658191 +perft 6 890966633 + +id 1 +epd qbrnnkbr/1p2pp1p/p1p3p1/3p4/6P1/P1N4P/1PPPPP2/QBR1NKBR w HChc - 0 9 +perft 1 26 +perft 2 701 +perft 3 18930 +perft 4 521377 +perft 5 14733245 +perft 6 416881799 + +id 1 +epd qr1b1kbr/1p1ppppp/1n1n4/p1p5/4P3/5NPP/PPPP1P2/QRNB1KBR w HBhb - 1 9 +perft 1 26 +perft 2 649 +perft 3 17235 +perft 4 451997 +perft 5 12367604 +perft 6 342165821 + +id 1 +epd qrnnkb1r/1pppppp1/7p/p4b2/4P3/5P1P/PPPP2PR/QRNNKBB1 w Bhb - 1 9 +perft 1 34 +perft 2 941 +perft 3 31720 +perft 4 901240 +perft 5 30307554 +perft 6 888709821 + +id 1 +epd qr1nkrbb/p2ppppp/1pp5/8/3Pn3/1NP3P1/PP2PP1P/QR1NKRBB w FBfb - 1 9 +perft 1 19 +perft 2 505 +perft 3 11107 +perft 4 294251 +perft 5 7046501 +perft 6 190414579 + +id 1 +epd bbrqn1kr/1pppp1pp/4n3/5p2/p5P1/3P4/PPP1PPKP/BBRQNN1R w hc - 0 9 +perft 1 24 +perft 2 573 +perft 3 12963 +perft 4 335845 +perft 5 8191054 +perft 6 227555387 + +id 1 +epd brqb1nkr/pppppp1p/8/4N1pn/5P2/6P1/PPPPP2P/BRQB1NKR w HBhb - 0 9 +perft 1 26 +perft 2 550 +perft 3 14338 +perft 4 331666 +perft 5 8903754 +perft 6 223437427 + +id 1 +epd brqnn1kr/pp3ppp/2pbp3/3p4/8/2NPP3/PPP1BPPP/BRQ1N1KR w HBhb - 0 9 +perft 1 27 +perft 2 780 +perft 3 20760 +perft 4 589328 +perft 5 16243731 +perft 6 463883447 + +id 1 +epd brq1nkrb/ppp2ppp/8/n2pp2P/P7/4P3/1PPP1PP1/BRQNNKRB w GBgb - 1 9 +perft 1 17 +perft 2 426 +perft 3 8295 +perft 4 235162 +perft 5 5048497 +perft 6 153986034 + +id 1 +epd rbbqn1kr/pp2p1pp/6n1/2pp1p2/2P4P/P7/BP1PPPP1/R1BQNNKR w HAha - 0 9 +perft 1 27 +perft 2 916 +perft 3 25798 +perft 4 890435 +perft 5 26302461 +perft 6 924181432 + +id 1 +epd 1qbbn1kr/1ppppppp/r3n3/8/p1P5/P7/1P1PPPPP/RQBBNNKR w HAh - 1 9 +perft 1 29 +perft 2 817 +perft 3 24530 +perft 4 720277 +perft 5 22147642 +perft 6 670707652 + +id 1 +epd rqbnnbkr/ppp1ppp1/7p/3p4/PP6/7P/1NPPPPP1/RQB1NBKR w HAa - 1 9 +perft 1 23 +perft 2 572 +perft 3 14509 +perft 4 381474 +perft 5 10416981 +perft 6 288064942 + +id 1 +epd r1bnnkrb/q1ppp1pp/p7/1p3pB1/2P1P3/3P4/PP3PPP/RQ1NNKRB w GAga - 2 9 +perft 1 31 +perft 2 925 +perft 3 27776 +perft 4 860969 +perft 5 26316355 +perft 6 843078864 + +id 1 +epd rbqnb1kr/ppppp1pp/5p2/5N2/7P/1n3P2/PPPPP1P1/RBQNB1KR w HAha - 1 9 +perft 1 32 +perft 2 864 +perft 3 27633 +perft 4 766551 +perft 5 24738875 +perft 6 707188107 + +id 1 +epd rqnbbn1r/ppppppp1/6k1/8/6Pp/2PN4/PP1PPPKP/RQ1BBN1R w - - 0 9 +perft 1 27 +perft 2 566 +perft 3 15367 +perft 4 347059 +perft 5 9714509 +perft 6 234622128 + +id 1 +epd rqnnbbkr/p1p2pp1/1p1p3p/4p3/4NP2/6P1/PPPPP2P/RQN1BBKR w HAha - 0 9 +perft 1 27 +perft 2 631 +perft 3 17923 +perft 4 452734 +perft 5 13307890 +perft 6 356279813 + +id 1 +epd 1qnnbrkb/rppp1ppp/p3p3/8/4P3/2PP1P2/PP4PP/RQNNBKRB w GA - 1 9 +perft 1 24 +perft 2 479 +perft 3 12135 +perft 4 271469 +perft 5 7204345 +perft 6 175460841 + +id 1 +epd rbqnn1br/p1pppk1p/1p4p1/5p2/8/P1P2P2/1PBPP1PP/R1QNNKBR w HA - 0 9 +perft 1 31 +perft 2 756 +perft 3 23877 +perft 4 625194 +perft 5 20036784 +perft 6 554292502 + +id 1 +epd rqnbnkbr/1ppppp2/p5p1/8/1P4p1/4PP2/P1PP3P/RQNBNKBR w HAha - 0 9 +perft 1 24 +perft 2 715 +perft 3 18536 +perft 4 575589 +perft 5 16013189 +perft 6 515078271 + +id 1 +epd rq1nkbbr/1p2pppp/p2n4/2pp4/1P4P1/P2N4/2PPPP1P/RQ1NKBBR w HAha - 1 9 +perft 1 27 +perft 2 694 +perft 3 19840 +perft 4 552904 +perft 5 16685687 +perft 6 494574415 + +id 1 +epd r1nnkrbb/pp1pppp1/2p3q1/7p/8/1PPP3P/P3PPP1/RQNNKRBB w FAfa - 1 9 +perft 1 18 +perft 2 520 +perft 3 10808 +perft 4 329085 +perft 5 7508201 +perft 6 235103697 + +id 1 +epd bbrnqk1r/pppp3p/6p1/4pp2/3P2P1/8/PPP1PP1P/BBRN1NKR w HC - 0 9 +perft 1 22 +perft 2 566 +perft 3 12965 +perft 4 362624 +perft 5 8721079 +perft 6 259069471 + +id 1 +epd brnb1nkr/pppqpp2/3p2pp/8/3PP3/1P6/PBP2PPP/1RNBQNKR w HBhb - 0 9 +perft 1 32 +perft 2 859 +perft 3 28517 +perft 4 817464 +perft 5 27734108 +perft 6 829785474 + +id 1 +epd brnq1b1r/ppp1ppkp/3p1np1/8/8/5P1P/PPPPPKPR/BRNQNB2 w - - 0 9 +perft 1 21 +perft 2 511 +perft 3 10951 +perft 4 273756 +perft 5 6372681 +perft 6 167139732 + +id 1 +epd brnq1rkb/1pppppp1/3n3p/p7/8/P4NP1/1PPPPPRP/BRNQ1K1B w B - 0 9 +perft 1 25 +perft 2 548 +perft 3 14049 +perft 4 341208 +perft 5 9015901 +perft 6 235249649 + +id 1 +epd rbb1qnkr/p1ppp1pp/1p3p2/6n1/8/1PN1P2P/P1PP1PP1/RBB1QNKR w HAha - 0 9 +perft 1 25 +perft 2 673 +perft 3 16412 +perft 4 467660 +perft 5 12099119 +perft 6 361714466 + +id 1 +epd rnbb1nkr/1ppp1ppp/4p3/p5q1/6P1/1PP5/PB1PPP1P/RN1BQNKR w HAha - 1 9 +perft 1 19 +perft 2 663 +perft 3 14149 +perft 4 489653 +perft 5 11491355 +perft 6 399135495 + +id 1 +epd rnbqnbkr/1pp1p2p/3p1p2/p5p1/5PP1/2P5/PPNPP2P/RNBQ1BKR w HAha - 0 9 +perft 1 24 +perft 2 647 +perft 3 16679 +perft 4 461931 +perft 5 12649636 +perft 6 361157611 + +id 1 +epd rnb2krb/pppqppnp/8/3p2p1/1P4P1/7P/P1PPPPB1/RNBQNKR1 w GAga - 1 9 +perft 1 24 +perft 2 722 +perft 3 18749 +perft 4 605229 +perft 5 16609220 +perft 6 563558512 + +id 1 +epd rbnqb1kr/pppn1pp1/3p3p/4p3/1P6/P7/R1PPPPPP/1BNQBNKR w Hha - 1 9 +perft 1 20 +perft 2 538 +perft 3 12277 +perft 4 345704 +perft 5 8687621 +perft 6 255304141 + +id 1 +epd rnqb1nkr/p1pbp1pp/8/1pPp1p2/P2P4/8/1P2PPPP/RNQBBNKR w HAha - 1 9 +perft 1 35 +perft 2 764 +perft 3 26952 +perft 4 632796 +perft 5 22592380 +perft 6 564255328 + +id 1 +epd rnq1bbkr/1p1ppp1p/4n3/p1p3p1/P1PP4/8/RP2PPPP/1NQNBBKR w Hha - 0 9 +perft 1 29 +perft 2 709 +perft 3 21296 +perft 4 570580 +perft 5 17597398 +perft 6 506140370 + +id 1 +epd 1nqnbkrb/1pppp2p/r7/p4pp1/3P4/8/PPPBPPPP/RNQNK1RB w g - 0 9 +perft 1 27 +perft 2 1028 +perft 3 28534 +perft 4 1050834 +perft 5 30251988 +perft 6 1096869832 + +id 1 +epd rbnqnkbr/p1pp1p1p/8/1p2p3/3P2pP/2P5/PP2PPP1/RBNQNKBR w HAha - 0 9 +perft 1 32 +perft 2 832 +perft 3 27120 +perft 4 750336 +perft 5 24945574 +perft 6 724171581 + +id 1 +epd rnq1nkbr/1p1p1ppp/2p1pb2/p7/7P/2P5/PPNPPPPB/RNQB1K1R w HAha - 2 9 +perft 1 31 +perft 2 779 +perft 3 24010 +perft 4 638640 +perft 5 19919434 +perft 6 551494771 + +id 1 +epd rnqnk1br/p1ppp1bp/1p3p2/6p1/4N3/P5P1/1PPPPP1P/R1QNKBBR w HAha - 2 9 +perft 1 25 +perft 2 717 +perft 3 19396 +perft 4 576577 +perft 5 16525239 +perft 6 507175842 + +id 1 +epd rnq1krbb/p1p1pppp/8/1p1p4/1n5B/2N2P2/PPPPP1PP/RNQ1KR1B w FAfa - 0 9 +perft 1 28 +perft 2 867 +perft 3 24029 +perft 4 735686 +perft 5 21112751 +perft 6 654808184 + +id 1 +epd bbrnnqkr/1pp1pppp/3p4/p7/P3P3/7P/1PPP1PP1/BBRNNQKR w HChc - 0 9 +perft 1 24 +perft 2 405 +perft 3 11025 +perft 4 210557 +perft 5 6196438 +perft 6 131401224 + +id 1 +epd brnbnqkr/p1ppp3/1p5p/5Pp1/5P2/3N4/PPPPP2P/BRNB1QKR w HBhb g6 0 9 +perft 1 25 +perft 2 785 +perft 3 21402 +perft 4 698331 +perft 5 20687969 +perft 6 695850727 + +id 1 +epd br1nqbkr/1ppppp2/pn6/6pp/2PP4/1N4P1/PP2PP1P/BR1NQBKR w HBhb - 0 9 +perft 1 25 +perft 2 596 +perft 3 16220 +perft 4 421882 +perft 5 12185361 +perft 6 337805606 + +id 1 +epd 1rnnqkrb/p2ppp1p/1pp5/2N3p1/8/1P6/P1PPPPKP/BR1NQ1RB w gb - 0 9 +perft 1 38 +perft 2 960 +perft 3 34831 +perft 4 913665 +perft 5 32490040 +perft 6 880403591 + +id 1 +epd rbbnnqkr/pp3pp1/2p1p3/3p3p/3P3P/1PP5/P3PPP1/RBBNNQKR w HAha - 0 9 +perft 1 30 +perft 2 785 +perft 3 23079 +perft 4 656618 +perft 5 19885037 +perft 6 599219582 + +id 1 +epd rn1bnqkr/p1ppppp1/8/1p5p/P4P1P/3N4/1PPPP1b1/RNBB1QKR w HAha - 0 9 +perft 1 27 +perft 2 752 +perft 3 21735 +perft 4 613194 +perft 5 18862234 +perft 6 547415271 + +id 1 +epd 1nbnqbkr/1p1p1ppp/r3p3/p1p5/P3P3/3Q4/1PPP1PPP/RNBN1BKR w HAh - 2 9 +perft 1 33 +perft 2 721 +perft 3 24278 +perft 4 572535 +perft 5 19648535 +perft 6 496023732 + +id 1 +epd rnbnqkrb/2pppppp/1p6/p7/1PP5/4N2P/P2PPPP1/RNB1QKRB w GAg - 0 9 +perft 1 23 +perft 2 570 +perft 3 14225 +perft 4 374196 +perft 5 10022614 +perft 6 279545007 + +id 1 +epd rbnnbq1r/ppppppkp/6p1/N7/4P3/P7/1PPP1PPP/RB1NBQKR w HA - 5 9 +perft 1 27 +perft 2 620 +perft 3 18371 +perft 4 440594 +perft 5 13909432 +perft 6 349478320 + +id 1 +epd r1nbbqkr/pppppp1p/8/8/1n3Pp1/3N1QP1/PPPPP2P/RN1BB1KR w HAha - 0 9 +perft 1 31 +perft 2 791 +perft 3 25431 +perft 4 682579 +perft 5 22408813 +perft 6 636779732 + +id 1 +epd rnq1bbkr/pp1p1ppp/2pnp3/8/7P/1QP5/PP1PPPPR/RNN1BBK1 w Aha - 2 9 +perft 1 28 +perft 2 559 +perft 3 16838 +perft 4 390887 +perft 5 12242780 +perft 6 315431511 + +id 1 +epd rnnqbrkb/2ppppp1/1p1N4/p6p/4P3/8/PPPP1PPP/R1NQBKRB w GA - 0 9 +perft 1 32 +perft 2 638 +perft 3 20591 +perft 4 438792 +perft 5 14395828 +perft 6 331782223 + +id 1 +epd rbnnq1br/pppp1kp1/4pp2/7p/PP6/2PP4/4PPPP/RBNNQKBR w HA - 0 9 +perft 1 21 +perft 2 521 +perft 3 12201 +perft 4 320429 +perft 5 8239159 +perft 6 227346638 + +id 1 +epd rnnbqkbr/p2ppp2/7p/1pp3p1/2P2N2/8/PP1PPPPP/RN1BQKBR w HAha - 0 9 +perft 1 25 +perft 2 528 +perft 3 13896 +perft 4 326094 +perft 5 9079829 +perft 6 232750602 + +id 1 +epd rnn1kbbr/ppppqp2/6p1/2N1p2p/P7/2P5/1P1PPPPP/RN1QKBBR w HAha - 2 9 +perft 1 27 +perft 2 801 +perft 3 22088 +perft 4 707078 +perft 5 20334071 +perft 6 682580976 + +id 1 +epd rnnqkrbb/p1p1p1pp/1p3p2/8/3p2Q1/P1P1P3/1P1P1PPP/RNN1KRBB w FAfa - 0 9 +perft 1 37 +perft 2 1014 +perft 3 34735 +perft 4 998999 +perft 5 32921537 +perft 6 988770109 + +id 1 +epd bbrnk1qr/1pppppp1/p4n1p/8/P2P2N1/8/1PP1PPPP/BBR1NKQR w HC - 1 9 +perft 1 21 +perft 2 481 +perft 3 11213 +perft 4 279993 +perft 5 7015419 +perft 6 187564853 + +id 1 +epd brnbnkqr/1pp1p1p1/p2p1p2/7p/1P4PP/8/PBPPPP2/1RNBNKQR w HBhb - 0 9 +perft 1 31 +perft 2 743 +perft 3 24260 +perft 4 660177 +perft 5 22391185 +perft 6 653721389 + +id 1 +epd br2kbqr/ppppp1pp/3n1p2/3P4/3n3P/3N4/PPP1PPP1/BR1NKBQR w HBhb - 3 9 +perft 1 25 +perft 2 872 +perft 3 22039 +perft 4 748726 +perft 5 20281962 +perft 6 685749952 + +id 1 +epd br1nkqrb/ppppppp1/8/7p/4P3/n1P2PP1/PP1P3P/BRNNKQRB w GBgb - 0 9 +perft 1 28 +perft 2 607 +perft 3 16934 +perft 4 396483 +perft 5 11607818 +perft 6 294181806 + +id 1 +epd rbbn1kqr/pp1pp1p1/2pn3p/5p2/5P2/1P1N4/PNPPP1PP/RBB2KQR w HAha - 1 9 +perft 1 27 +perft 2 725 +perft 3 21543 +perft 4 616082 +perft 5 19239812 +perft 6 581716972 + +id 1 +epd rnbbnk1r/pp1ppp1p/6q1/2p5/PP4p1/4P3/2PP1PPP/RNBBNKQR w HAha - 1 9 +perft 1 25 +perft 2 1072 +perft 3 26898 +perft 4 1088978 +perft 5 28469879 +perft 6 1122703887 + +id 1 +epd rnbnkbqr/1pp3pp/3p4/p3pp2/3P2P1/2N1N3/PPP1PP1P/R1B1KBQR w HAha - 0 9 +perft 1 31 +perft 2 1028 +perft 3 32907 +perft 4 1095472 +perft 5 36025223 +perft 6 1211187800 + +id 1 +epd r1bnkqrb/1ppppppp/p3n3/8/6P1/4N3/PPPPPPRP/RNB1KQ1B w Aga - 1 9 +perft 1 23 +perft 2 457 +perft 3 11416 +perft 4 250551 +perft 5 6666787 +perft 6 159759052 + +id 1 +epd rbn1bkqr/p1pp1pp1/1pn5/4p2p/7P/1PBP4/P1P1PPP1/RBNN1KQR w HAha - 0 9 +perft 1 23 +perft 2 470 +perft 3 11649 +perft 4 264274 +perft 5 6963287 +perft 6 172833738 + +id 1 +epd rnnbbkqr/3ppppp/p7/1pp5/P6P/6P1/1PPPPP2/RNNBBKQR w HAha - 0 9 +perft 1 26 +perft 2 569 +perft 3 15733 +perft 4 375556 +perft 5 11008114 +perft 6 284485303 + +id 1 +epd r1nk1bqr/1pppp1pp/2n5/p4p1b/5P2/1N4B1/PPPPP1PP/RN1K1BQR w HAha - 2 9 +perft 1 25 +perft 2 824 +perft 3 21983 +perft 4 738366 +perft 5 20904119 +perft 6 716170771 + +id 1 +epd r1nkbqrb/p2pppp1/npp4p/8/4PP2/2N4P/PPPP2P1/R1NKBQRB w GAga - 0 9 +perft 1 31 +perft 2 548 +perft 3 17480 +perft 4 349633 +perft 5 11469548 +perft 6 255067638 + +id 1 +epd rbnnkqbr/ppppp2p/5p2/6p1/2P1B3/P6P/1P1PPPP1/R1NNKQBR w HAha - 1 9 +perft 1 31 +perft 2 809 +perft 3 24956 +perft 4 680747 +perft 5 21247414 +perft 6 606221516 + +id 1 +epd 1r1bkqbr/pppp1ppp/2nnp3/8/2P5/N4P2/PP1PP1PP/1RNBKQBR w Hh - 0 9 +perft 1 28 +perft 2 810 +perft 3 22844 +perft 4 694599 +perft 5 20188622 +perft 6 636748147 + +id 1 +epd rn1kqbbr/p1pppp1p/1p4p1/1n6/1P2P3/4Q2P/P1PP1PP1/RNNK1BBR w HAha - 1 9 +perft 1 39 +perft 2 848 +perft 3 30100 +perft 4 724426 +perft 5 25594662 +perft 6 659615710 + +id 1 +epd rn1kqrbb/pppppppp/8/8/2nP2P1/1P2P3/P1P2P1P/RNNKQRBB w FAfa - 1 9 +perft 1 29 +perft 2 766 +perft 3 21701 +perft 4 567971 +perft 5 16944425 +perft 6 456898648 + +id 1 +epd b1rnnkrq/bpppppp1/7p/8/1p6/2B5/PNPPPPPP/1BR1NKRQ w GCgc - 2 9 +perft 1 25 +perft 2 667 +perft 3 17253 +perft 4 472678 +perft 5 12865247 +perft 6 365621294 + +id 1 +epd brnb1krq/pppppppp/8/5P2/2P1n2P/8/PP1PP1P1/BRNBNKRQ w GBgb - 1 9 +perft 1 23 +perft 2 620 +perft 3 14882 +perft 4 402561 +perft 5 10776855 +perft 6 300125003 + +id 1 +epd b1nnkbrq/pr1pppp1/1p5p/2p5/P2N1P2/8/1PPPP1PP/BR1NKBRQ w GBg - 0 9 +perft 1 24 +perft 2 472 +perft 3 12181 +perft 4 267398 +perft 5 7370758 +perft 6 178605165 + +id 1 +epd br1nkrqb/p1p1p1pp/3n4/1p1p1p2/5N1P/4P3/PPPP1PP1/BR1NKRQB w FBfb - 0 9 +perft 1 24 +perft 2 775 +perft 3 19398 +perft 4 624309 +perft 5 16429837 +perft 6 539767605 + +id 1 +epd rbbnnkrq/p2pp1pp/2p5/5p2/1pPP1B2/P7/1P2PPPP/RB1NNKRQ w GAga - 0 9 +perft 1 34 +perft 2 921 +perft 3 30474 +perft 4 849933 +perft 5 28095833 +perft 6 806446436 + +id 1 +epd rnbbnkr1/1p1ppp1p/2p3p1/p7/2Pq4/1P1P4/P2BPPPP/RN1BNKRQ w GAga - 2 9 +perft 1 26 +perft 2 1139 +perft 3 29847 +perft 4 1204863 +perft 5 32825932 +perft 6 1281760240 + +id 1 +epd 1rbnkbrq/pppppp2/n5pp/2P5/P7/4N3/1P1PPPPP/RNB1KBRQ w GAg - 2 9 +perft 1 23 +perft 2 574 +perft 3 14146 +perft 4 391413 +perft 5 10203438 +perft 6 301874034 + +id 1 +epd 1nbnkr1b/rppppppq/p7/7p/1P5P/3P2P1/P1P1PP2/RNBNKRQB w FAf - 1 9 +perft 1 33 +perft 2 823 +perft 3 26696 +perft 4 724828 +perft 5 23266182 +perft 6 672294132 + +id 1 +epd rbn1bkrq/ppppp3/4n2p/5pp1/1PN5/2P5/P2PPPPP/RBN1BKRQ w GAga - 0 9 +perft 1 27 +perft 2 859 +perft 3 24090 +perft 4 796482 +perft 5 23075785 +perft 6 789152120 + +id 1 +epd r1nbbkrq/1ppp2pp/2n2p2/p3p3/5P2/1N4BP/PPPPP1P1/RN1B1KRQ w GAga - 0 9 +perft 1 25 +perft 2 774 +perft 3 20141 +perft 4 618805 +perft 5 16718577 +perft 6 515864053 + +id 1 +epd rnnkbbrq/1pppp1p1/5p2/7p/p6P/3N1P2/PPPPP1PQ/RN1KBBR1 w GAga - 0 9 +perft 1 29 +perft 2 673 +perft 3 20098 +perft 4 504715 +perft 5 15545590 +perft 6 416359581 + +id 1 +epd r1nkbrqb/pppp1p2/n3p1p1/7p/2P2P2/1P6/P2PPQPP/RNNKBR1B w FAfa - 0 9 +perft 1 27 +perft 2 722 +perft 3 21397 +perft 4 593762 +perft 5 18742426 +perft 6 537750982 + +id 1 +epd rbnnkr1q/1ppp2pp/p4p2/P2bp3/4P2P/8/1PPP1PP1/RBNNKRBQ w FAfa - 1 9 +perft 1 26 +perft 2 848 +perft 3 23387 +perft 4 741674 +perft 5 21591790 +perft 6 675163653 + +id 1 +epd rn1bkrb1/1ppppp1p/pn4p1/8/P2q3P/3P4/NPP1PPP1/RN1BKRBQ w FAfa - 1 9 +perft 1 22 +perft 2 803 +perft 3 18322 +perft 4 632920 +perft 5 15847763 +perft 6 536419559 + +id 1 +epd rn1krbbq/pppp1npp/4pp2/8/4P2P/3P2P1/PPP2P2/RNNKRBBQ w EAea - 1 9 +perft 1 29 +perft 2 810 +perft 3 23968 +perft 4 670500 +perft 5 20361517 +perft 6 575069358 + +id 1 +epd rnn1rqbb/ppkp1pp1/2p1p2p/2P5/8/3P1P2/PP2P1PP/RNNKRQBB w EA - 0 9 +perft 1 22 +perft 2 506 +perft 3 11973 +perft 4 292344 +perft 5 7287368 +perft 6 189865944 + +id 1 +epd bbqr1knr/pppppp1p/8/4n1p1/2P1P3/6P1/PPQP1P1P/BB1RNKNR w HDhd - 0 9 +perft 1 26 +perft 2 650 +perft 3 18253 +perft 4 481200 +perft 5 14301029 +perft 6 394943978 + +id 1 +epd bq1bnknr/pprppp1p/8/2p3p1/4PPP1/8/PPPP3P/BQRBNKNR w HCh - 0 9 +perft 1 24 +perft 2 548 +perft 3 14021 +perft 4 347611 +perft 5 9374021 +perft 6 250988458 + +id 1 +epd bqrnkb1r/1p2pppp/p1pp3n/5Q2/2P4P/5N2/PP1PPPP1/B1RNKB1R w HChc - 0 9 +perft 1 46 +perft 2 823 +perft 3 33347 +perft 4 673905 +perft 5 26130444 +perft 6 582880996 + +id 1 +epd bq1rknrb/pppppp1p/4n3/6p1/4P1P1/3P1P2/PPP4P/BQRNKNRB w GCg - 0 9 +perft 1 23 +perft 2 618 +perft 3 14815 +perft 4 419474 +perft 5 10606831 +perft 6 315124518 + +id 1 +epd q1brnknr/pp1pp1p1/8/2p2p1p/5b2/P4N2/1PPPP1PP/QBBRK1NR w hd - 0 9 +perft 1 22 +perft 2 675 +perft 3 15778 +perft 4 473994 +perft 5 12077228 +perft 6 368479752 + +id 1 +epd qrbbnknr/1p1ppp1p/p1p5/8/1P2P1p1/3P1B2/P1P2PPP/QRB1NKNR w HBhb - 0 9 +perft 1 32 +perft 2 722 +perft 3 24049 +perft 4 569905 +perft 5 19584539 +perft 6 484814878 + +id 1 +epd qrb1kbnr/p3pppp/2n5/1ppp4/7P/3P1P2/PPP1P1PR/QRBNKBN1 w Bhb - 0 9 +perft 1 26 +perft 2 831 +perft 3 22606 +perft 4 724505 +perft 5 20500804 +perft 6 662608969 + +id 1 +epd qrbnknrb/ppp1pp2/6p1/7p/PPNp4/8/2PPPPPP/QRB1KNRB w GBgb - 0 9 +perft 1 31 +perft 2 840 +perft 3 26762 +perft 4 742772 +perft 5 24422614 +perft 6 701363800 + +id 1 +epd qbrnbknr/pp1pp1pp/8/2p2p2/3Q4/PP6/2PPPPPP/1BRNBKNR w HChc - 0 9 +perft 1 38 +perft 2 1121 +perft 3 39472 +perft 4 1198438 +perft 5 41108769 +perft 6 1285503872 + +id 1 +epd qr1bbk1r/pppppp1p/1n6/5np1/4B3/1PP5/P2PPPPP/QRN1BKNR w HBhb - 0 9 +perft 1 25 +perft 2 694 +perft 3 16938 +perft 4 472950 +perft 5 12164609 +perft 6 345122090 + +id 1 +epd qrnkbbnr/1p1pp2p/p7/2p1Npp1/6P1/7P/PPPPPP2/QR1KBBNR w HBhb - 0 9 +perft 1 27 +perft 2 586 +perft 3 16348 +perft 4 393391 +perft 5 11409633 +perft 6 298054792 + +id 1 +epd qrnkbnrb/pp1p1p2/2p1p1pp/4N3/P4P2/8/1PPPP1PP/QR1KBNRB w GBgb - 0 9 +perft 1 32 +perft 2 645 +perft 3 20737 +perft 4 460319 +perft 5 15037464 +perft 6 358531599 + +id 1 +epd qbrnknbr/1pppppp1/p6p/8/1P6/3PP3/PQP2PPP/1BRNKNBR w HChc - 3 9 +perft 1 26 +perft 2 595 +perft 3 16755 +perft 4 415022 +perft 5 12214768 +perft 6 323518628 + +id 1 +epd qrnbk1br/1ppppp1p/p5p1/8/4Pn2/4K1P1/PPPP1P1P/QRNB1NBR w hb - 0 9 +perft 1 24 +perft 2 609 +perft 3 13776 +perft 4 359415 +perft 5 8538539 +perft 6 230364479 + +id 1 +epd qrnk1bbr/1pnp1ppp/p1p1p3/8/3Q4/1P1N3P/P1PPPPP1/1RNK1BBR w HBhb - 0 9 +perft 1 43 +perft 2 1106 +perft 3 42898 +perft 4 1123080 +perft 5 41695761 +perft 6 1113836402 + +id 1 +epd qrnknrb1/pppppp2/8/6pp/4P2P/3P1P2/PbP3P1/QRNKNRBB w FBfb - 0 9 +perft 1 24 +perft 2 658 +perft 3 17965 +perft 4 488373 +perft 5 14457245 +perft 6 400971226 + +id 1 +epd bbrqnrk1/ppp2ppp/7n/3pp3/8/P4N1N/1PPPPPPP/BBRQ1RK1 w - - 1 9 +perft 1 22 +perft 2 503 +perft 3 12078 +perft 4 310760 +perft 5 8080951 +perft 6 224960353 + +id 1 +epd brqbnk1r/1ppp1ppp/8/p3pn2/8/2PP1P2/PP2PKPP/BRQBN1NR w hb - 1 9 +perft 1 25 +perft 2 745 +perft 3 19387 +perft 4 570459 +perft 5 15520298 +perft 6 460840861 + +id 1 +epd brqnkbnr/pp2pp1p/3p4/2p5/5p2/3P3P/PPP1PPP1/B1RNKBNR w Hhb - 0 9 +perft 1 19 +perft 2 516 +perft 3 10755 +perft 4 312996 +perft 5 6995034 +perft 6 214340699 + +id 1 +epd brq1kn1b/1ppppprp/2n3p1/p7/P1N5/6P1/1PPPPP1P/BRQNK1RB w GBb - 2 9 +perft 1 29 +perft 2 557 +perft 3 16739 +perft 4 352277 +perft 5 10840256 +perft 6 249999654 + +id 1 +epd rbbq1k1r/ppp1pppp/7n/1n1p4/5P2/P2P4/1PPBP1PP/RB1QNKNR w HAha - 1 9 +perft 1 25 +perft 2 769 +perft 3 20110 +perft 4 638340 +perft 5 17438715 +perft 6 570893953 + +id 1 +epd r1bbnk1r/qpp1pppp/p6n/3p4/1P6/5N1P/P1PPPPP1/RQBBK1NR w ha - 0 9 +perft 1 23 +perft 2 728 +perft 3 18209 +perft 4 587364 +perft 5 16053564 +perft 6 529082811 + +id 1 +epd rqbnkbnr/1pp2p1p/3p4/p3p1p1/8/2P2P2/PP1PPNPP/RQBNKB1R w HAha - 0 9 +perft 1 26 +perft 2 772 +perft 3 21903 +perft 4 653704 +perft 5 19571559 +perft 6 593915677 + +id 1 +epd r1bnknrb/pqppp1p1/1p5p/5p2/7P/3P2N1/PPP1PPP1/RQBNK1RB w GAga - 2 9 +perft 1 27 +perft 2 748 +perft 3 20291 +perft 4 597105 +perft 5 16324542 +perft 6 506453626 + +id 1 +epd rbqnbknr/pp1pppp1/8/2p5/3P3p/5N1P/PPP1PPPR/RBQNBK2 w Aha - 0 9 +perft 1 30 +perft 2 859 +perft 3 26785 +perft 4 819631 +perft 5 26363334 +perft 6 842796987 + +id 1 +epd rqnbbrk1/ppppppp1/8/5n1p/3P3P/2B3P1/PPP1PP2/RQNB1KNR w HA - 0 9 +perft 1 22 +perft 2 505 +perft 3 11452 +perft 4 283464 +perft 5 7055215 +perft 6 186760784 + +id 1 +epd rqnkbbnr/pp2p1p1/8/2pp1p1p/3PPP2/8/PPP1N1PP/RQNKBB1R w HAha - 0 9 +perft 1 28 +perft 2 832 +perft 3 23142 +perft 4 722857 +perft 5 20429246 +perft 6 663183060 + +id 1 +epd rqnkbnr1/pppp2bp/6p1/4pp2/1P2P3/3NN3/P1PP1PPP/RQ1KB1RB w GAga - 0 9 +perft 1 28 +perft 2 641 +perft 3 18835 +perft 4 459993 +perft 5 14038570 +perft 6 364210162 + +id 1 +epd rbq2kbr/pppppppp/2n5/P7/3P1n2/2P5/1P2PPPP/RBQNKNBR w HA - 1 9 +perft 1 31 +perft 2 889 +perft 3 27028 +perft 4 766181 +perft 5 24299415 +perft 6 692180754 + +id 1 +epd rq1bkn1r/ppppp2p/3n4/5pp1/2b3P1/1N1P1P2/PPP1P2P/RQ1BKNBR w HAha - 1 9 +perft 1 28 +perft 2 810 +perft 3 22667 +perft 4 657520 +perft 5 18719949 +perft 6 556282676 + +id 1 +epd r1nknbbr/p2ppp1p/1pp3p1/8/1P6/4P3/P1PPNPPq/R1QKNBBR w HAha - 0 9 +perft 1 24 +perft 2 797 +perft 3 22144 +perft 4 719069 +perft 5 21862776 +perft 6 716521139 + +id 1 +epd rqnknrbb/ppp1p3/5ppp/2Np4/2P5/4P3/PP1P1PPP/RQNK1RBB w FAfa - 0 9 +perft 1 34 +perft 2 686 +perft 3 23277 +perft 4 515541 +perft 5 17664543 +perft 6 423574794 + +id 1 +epd 1brnqknr/2p1pppp/p2p4/1P6/6P1/4Nb2/PP1PPP1P/BBR1QKNR w HChc - 1 9 +perft 1 34 +perft 2 1019 +perft 3 32982 +perft 4 1003103 +perft 5 33322477 +perft 6 1043293394 + +id 1 +epd brn1qknr/1p1pppp1/pb5p/Q1p5/3P3P/8/PPP1PPPR/BRNB1KN1 w Bhb - 2 9 +perft 1 32 +perft 2 642 +perft 3 20952 +perft 4 464895 +perft 5 15454749 +perft 6 371861782 + +id 1 +epd brnqkbnr/pppppp2/8/6pp/6P1/P2P1P2/1PP1P2P/BRNQKBNR w HBhb - 0 9 +perft 1 20 +perft 2 441 +perft 3 9782 +perft 4 240220 +perft 5 5770284 +perft 6 153051835 + +id 1 +epd 2nqknrb/1rpppppp/5B2/pp6/1PP1b3/3P4/P3PPPP/1RNQKNRB w GBg - 1 9 +perft 1 35 +perft 2 1042 +perft 3 36238 +perft 4 1101159 +perft 5 38505058 +perft 6 1202668717 + +id 1 +epd rb1nqknr/1pp1pppp/8/3p4/p2P4/6PN/PPPQPP1P/RBBN1K1R w HAha - 0 9 +perft 1 29 +perft 2 692 +perft 3 21237 +perft 4 555018 +perft 5 17820605 +perft 6 497251206 + +id 1 +epd rnbbqknr/pppp4/5p2/4p1pp/P7/2N2PP1/1PPPP2P/R1BBQKNR w HAha - 0 9 +perft 1 23 +perft 2 595 +perft 3 14651 +perft 4 415772 +perft 5 10881112 +perft 6 329010121 + +id 1 +epd rn1qkbnr/p1p1pp1p/bp4p1/3p4/1P6/4P3/P1PP1PPP/RNBQKBNR w HAha - 0 9 +perft 1 30 +perft 2 794 +perft 3 24319 +perft 4 690811 +perft 5 21657601 +perft 6 647745807 + +id 1 +epd r1bqk1rb/pppnpppp/5n2/3p4/2P3PP/2N5/PP1PPP2/R1BQKNRB w GAga - 1 9 +perft 1 32 +perft 2 821 +perft 3 27121 +perft 4 733155 +perft 5 24923473 +perft 6 710765657 + +id 1 +epd rbnqbknr/1p1ppp1p/6p1/p1p5/7P/3P4/PPP1PPP1/RBNQBKNR w HAha - 0 9 +perft 1 24 +perft 2 720 +perft 3 18842 +perft 4 575027 +perft 5 15992882 +perft 6 501093456 + +id 1 +epd r1qbbk1r/pp1ppppp/n1p5/5n2/B1P3P1/8/PP1PPP1P/RNQ1BKNR w HAha - 0 9 +perft 1 27 +perft 2 831 +perft 3 22293 +perft 4 698986 +perft 5 19948650 +perft 6 637973209 + +id 1 +epd rnqkbb1r/p1pppppp/8/8/1p4n1/PP4PP/2PPPP2/RNQKBBNR w HAha - 0 9 +perft 1 18 +perft 2 463 +perft 3 9519 +perft 4 256152 +perft 5 6065231 +perft 6 172734380 + +id 1 +epd rnqk1nrb/pppbpp2/7p/3p2p1/4B3/2N1N1P1/PPPPPP1P/R1QKB1R1 w GAga - 0 9 +perft 1 34 +perft 2 1171 +perft 3 38128 +perft 4 1318217 +perft 5 42109356 +perft 6 1465473753 + +id 1 +epd rbnqknbr/1pp1ppp1/3p4/7p/p2P2PP/2P5/PP2PP2/RBNQKNBR w HAha - 0 9 +perft 1 32 +perft 2 867 +perft 3 28342 +perft 4 798722 +perft 5 26632459 +perft 6 781067145 + +id 1 +epd rn1bknbr/pq2pppp/1p6/2pp4/P7/1P1P4/2PNPPPP/RNQBK1BR w HAha - 0 9 +perft 1 24 +perft 2 627 +perft 3 16652 +perft 4 462942 +perft 5 13200921 +perft 6 385193532 + +id 1 +epd r1qk1bbr/ppp1pp1p/2np1n2/6p1/2PP4/3BP3/PP3PPP/RNQKN1BR w HAha - 2 9 +perft 1 31 +perft 2 992 +perft 3 30213 +perft 4 986631 +perft 5 30397368 +perft 6 1011631987 + +id 1 +epd r1qknrbb/pppp1p2/2n3p1/4p2p/8/QPP5/P1NPPPPP/RN1K1RBB w FAfa - 2 9 +perft 1 30 +perft 2 702 +perft 3 21563 +perft 4 532939 +perft 5 16813114 +perft 6 438096194 + +id 1 +epd bbkr1qnr/2pppppp/2n5/pp6/8/PPN5/1BPPPPPP/1BR1KQNR w HC - 2 9 +perft 1 25 +perft 2 573 +perft 3 15183 +perft 4 380910 +perft 5 10554668 +perft 6 283975400 + +id 1 +epd 1rnbkqnr/1bpppppp/1p6/7P/p2P4/5P2/PPP1P1P1/BRNBKQNR w HBhb - 0 9 +perft 1 21 +perft 2 503 +perft 3 11790 +perft 4 301084 +perft 5 7679979 +perft 6 207799378 + +id 1 +epd brnkqbnr/2p1pppp/1p6/3p4/1pP5/P6P/3PPPP1/BRNKQBNR w HBhb - 0 9 +perft 1 28 +perft 2 743 +perft 3 21054 +perft 4 587192 +perft 5 17354516 +perft 6 507176753 + +id 1 +epd br1kqnrb/npp1pppp/8/3p4/p4N2/PP6/2PPPPPP/BR1KQNRB w GBgb - 0 9 +perft 1 31 +perft 2 808 +perft 3 25585 +perft 4 698475 +perft 5 22376575 +perft 6 640362920 + +id 1 +epd rbbnkq1r/pppppp1p/7n/6p1/P5P1/2P2N2/1P1PPP1P/RBBNKQ1R w HAha - 1 9 +perft 1 29 +perft 2 580 +perft 3 17585 +perft 4 404831 +perft 5 12730970 +perft 6 325226128 + +id 1 +epd rnbbk1nr/pp2qppp/2ppp3/8/3P4/P1N4N/1PP1PPPP/R1BBKQ1R w HAha - 0 9 +perft 1 29 +perft 2 838 +perft 3 24197 +perft 4 721884 +perft 5 21100580 +perft 6 646624429 + +id 1 +epd rnbk1b1r/ppppn1pp/4pp2/7q/7P/P5PB/1PPPPP2/RNBKQ1NR w HAha - 3 9 +perft 1 20 +perft 2 729 +perft 3 16633 +perft 4 576199 +perft 5 14507076 +perft 6 498621813 + +id 1 +epd r2kqnrb/pbppppp1/np5p/8/4Q1P1/3P4/PPP1PP1P/RNBK1NRB w GAga - 2 9 +perft 1 47 +perft 2 1219 +perft 3 55009 +perft 4 1486353 +perft 5 65239153 +perft 6 1834391369 + +id 1 +epd rbnkbq1r/p1p2ppp/1p2pn2/3p4/P3P3/3P4/1PP1KPPP/RBN1BQNR w ha - 2 9 +perft 1 29 +perft 2 923 +perft 3 27179 +perft 4 883866 +perft 5 26202752 +perft 6 868565895 + +id 1 +epd rk1bb1nr/ppppqppp/n7/1N2p3/6P1/7N/PPPPPP1P/R1KBBQ1R w HA - 6 9 +perft 1 27 +perft 2 703 +perft 3 19478 +perft 4 559525 +perft 5 16049807 +perft 6 492966455 + +id 1 +epd rnkqbbnr/p1ppp2p/1p4p1/8/1B3p1P/2NP4/PPP1PPP1/R1KQ1BNR w HAha - 0 9 +perft 1 29 +perft 2 610 +perft 3 18855 +perft 4 438277 +perft 5 14020041 +perft 6 355083962 + +id 1 +epd rnkqb1rb/pp1p1ppp/4p3/2P3n1/8/1PP5/P3PPPP/RNKQBNRB w GAga - 0 9 +perft 1 29 +perft 2 675 +perft 3 20699 +perft 4 535821 +perft 5 17000613 +perft 6 476598337 + +id 1 +epd rb1kqnbr/pp1pp1p1/1np2p2/7p/P1P3PP/8/1P1PPP2/RBNKQNBR w HAha - 0 9 +perft 1 31 +perft 2 1077 +perft 3 33661 +perft 4 1183381 +perft 5 37415304 +perft 6 1328374620 + +id 1 +epd rnkbq1br/ppp2ppp/3p4/Q3p1n1/5P2/3P2P1/PPP1P2P/RNKB1NBR w HAha - 0 9 +perft 1 41 +perft 2 1201 +perft 3 46472 +perft 4 1420367 +perft 5 52991625 +perft 6 1675608008 + +id 1 +epd rn1qnbbr/pp2pppp/2ppk3/8/2PP4/3Q1N2/PP2PPPP/RNK2BBR w HA - 1 9 +perft 1 34 +perft 2 666 +perft 3 22474 +perft 4 472299 +perft 5 15860369 +perft 6 353831792 + +id 1 +epd rnkqnr1b/ppppp1pp/5p2/8/Q1P2P2/8/PP1P2PP/RbK1NRBB w FAfa - 0 9 +perft 1 36 +perft 2 876 +perft 3 31987 +perft 4 788580 +perft 5 29022529 +perft 6 736717252 + +id 1 +epd bbrn1nqr/ppp1k1pp/5p2/3pp3/7P/3PN3/PPP1PPP1/BBRK1NQR w - - 1 9 +perft 1 24 +perft 2 583 +perft 3 15063 +perft 4 383532 +perft 5 10522064 +perft 6 280707118 + +id 1 +epd brnbkn1r/1pppp1p1/4q3/p4p1p/7P/1N3P2/PPPPP1PQ/BR1BKN1R w HBhb - 2 9 +perft 1 27 +perft 2 935 +perft 3 26120 +perft 4 885699 +perft 5 26000648 +perft 6 873063158 + +id 1 +epd br1knbqr/pp2p1pp/1n6/2pp1p2/6P1/2P4B/PP1PPPQP/BRNKN2R w HBhb - 0 9 +perft 1 27 +perft 2 681 +perft 3 19202 +perft 4 510687 +perft 5 14954779 +perft 6 415624943 + +id 1 +epd brnk1qrb/p1ppppp1/1p5p/8/P3n3/1N4P1/1PPPPPRP/BR1KNQ1B w Bgb - 0 9 +perft 1 22 +perft 2 638 +perft 3 13991 +perft 4 412346 +perft 5 9760752 +perft 6 293499724 + +id 1 +epd rbbnknqr/pppp3p/5pp1/8/1P1pP3/7P/P1P2PP1/RBBNKNQR w HAha - 0 9 +perft 1 29 +perft 2 756 +perft 3 21616 +perft 4 614074 +perft 5 17602252 +perft 6 528140595 + +id 1 +epd 1nbbknqr/rpp1ppp1/1Q1p3p/p7/2P2PP1/8/PP1PP2P/RNBBKN1R w HAh - 2 9 +perft 1 37 +perft 2 977 +perft 3 34977 +perft 4 944867 +perft 5 33695089 +perft 6 940198007 + +id 1 +epd rnb2bqr/ppkpppp1/3n3p/2p5/6PP/2N2P2/PPPPP3/R1BKNBQR w HA - 2 9 +perft 1 30 +perft 2 647 +perft 3 20365 +perft 4 467780 +perft 5 15115531 +perft 6 369257622 + +id 1 +epd rn1k1qrb/p1pppppp/bp6/8/4n3/P4BPP/1PPPPP2/RNBKNQR1 w GAga - 2 9 +perft 1 22 +perft 2 670 +perft 3 14998 +perft 4 451517 +perft 5 11199653 +perft 6 339919682 + +id 1 +epd rb2bnqr/nppkpppp/3p4/p7/1P6/P2N2P1/2PPPP1P/RB1KBNQR w HA - 3 9 +perft 1 22 +perft 2 479 +perft 3 11475 +perft 4 264739 +perft 5 6831555 +perft 6 167329117 + +id 1 +epd r1kbb1qr/2pppppp/np2n3/p7/2P3P1/8/PP1PPPQP/RNKBBN1R w HAha - 1 9 +perft 1 32 +perft 2 723 +perft 3 23953 +perft 4 581832 +perft 5 19472074 +perft 6 504622114 + +id 1 +epd rnknbb1r/p1ppp1pp/8/1p1P1p1q/8/P1P5/1P2PPPP/RNKNBBQR w HAha - 1 9 +perft 1 19 +perft 2 607 +perft 3 12733 +perft 4 417451 +perft 5 9753617 +perft 6 325177085 + +id 1 +epd rnkn1qrb/pp1bp1pp/2p5/1N1p1p2/8/2P5/PPKPPPPP/R2NBQRB w ga - 2 9 +perft 1 27 +perft 2 533 +perft 3 14549 +perft 4 330747 +perft 5 9206957 +perft 6 232664675 + +id 1 +epd r1nknqbr/pp2p1pp/2p2p2/3p4/6P1/PP1P4/2P1PP1b/RBNKNQBR w HAha - 0 9 +perft 1 20 +perft 2 582 +perft 3 13777 +perft 4 409166 +perft 5 10708639 +perft 6 326565393 + +id 1 +epd rnkb1qbr/p1pp1p1p/1p2pn2/1Q4p1/4P3/N4P2/PPPP2PP/R1KBN1BR w HAha - 0 9 +perft 1 40 +perft 2 1038 +perft 3 39356 +perft 4 1051441 +perft 5 39145902 +perft 6 1079612614 + +id 1 +epd rn2qbbr/1pkppp1p/p3n1p1/8/8/2P2P2/PP1PP1PP/RNKN1BBR w HA - 0 9 +perft 1 24 +perft 2 605 +perft 3 14888 +perft 4 385964 +perft 5 9687507 +perft 6 260874068 + +id 1 +epd rn1nqrbb/p1kppp1p/8/1pp3p1/1P6/2N1P3/P1PP1PPP/RK1NQRBB w - - 0 9 +perft 1 21 +perft 2 540 +perft 3 12489 +perft 4 337997 +perft 5 8436136 +perft 6 237525904 + +id 1 +epd bbrnknrq/1pp3pp/p2p1p2/4p3/P7/1P2N3/2PPPPPP/BBRN1RKQ w gc - 0 9 +perft 1 24 +perft 2 527 +perft 3 13900 +perft 4 326175 +perft 5 9139962 +perft 6 226253685 + +id 1 +epd brnb1nrq/pppp1kpp/4p3/8/5p1P/P1P3P1/1P1PPP2/BRNBKNRQ w GB - 1 9 +perft 1 29 +perft 2 773 +perft 3 23904 +perft 4 638768 +perft 5 20503775 +perft 6 560338709 + +id 1 +epd br1k1brq/ppppp2p/1n1n1pp1/8/P1P5/3P2P1/1P2PP1P/BRNKNBRQ w GBgb - 0 9 +perft 1 28 +perft 2 811 +perft 3 23550 +perft 4 664880 +perft 5 19913758 +perft 6 565143976 + +id 1 +epd 1r1knrqb/n1pppppp/p1b5/1p6/8/3N1P2/PPPPP1PP/BRNK1RQB w fb - 3 9 +perft 1 29 +perft 2 753 +perft 3 23210 +perft 4 620019 +perft 5 20044474 +perft 6 558383603 + +id 1 +epd rbbnk1rq/pppppppp/8/3Pn3/8/4P1P1/PPP2P1P/RBBNKNRQ w GAga - 1 9 +perft 1 22 +perft 2 551 +perft 3 12619 +perft 4 324608 +perft 5 8204171 +perft 6 217689974 + +id 1 +epd rnbbk1rq/2pppp1p/p3n1p1/1p6/P3N3/8/1PPPPPPP/RNBB1KRQ w ga - 0 9 +perft 1 26 +perft 2 742 +perft 3 20061 +perft 4 599527 +perft 5 16787080 +perft 6 525678162 + +id 1 +epd rnbkn1rq/ppppppb1/6p1/7p/2B2P2/1P2P3/P1PP2PP/RNBKN1RQ w GAga - 1 9 +perft 1 28 +perft 2 799 +perft 3 23210 +perft 4 689436 +perft 5 20755098 +perft 6 639632905 + +id 1 +epd rn1knrqb/p2pppp1/b1p5/1p5p/2P2P2/1P6/P2PP1PP/RNBKNRQB w FAfa - 1 9 +perft 1 30 +perft 2 579 +perft 3 18481 +perft 4 397545 +perft 5 13257198 +perft 6 311282465 + +id 1 +epd rbnkbnrq/pp2p1Np/2p2p2/8/3p4/8/PPPPPPPP/RBNKBR1Q w Aga - 0 9 +perft 1 23 +perft 2 670 +perft 3 16435 +perft 4 501883 +perft 5 13012378 +perft 6 411860744 + +id 1 +epd rk1bbnrq/ppp1pppp/n7/3p4/5P2/3P2NP/PPP1P1P1/RNKBB1RQ w GA - 0 9 +perft 1 26 +perft 2 597 +perft 3 16238 +perft 4 402506 +perft 5 11269462 +perft 6 296701249 + +id 1 +epd r1knbbrq/pppp2p1/2n1p2p/5p2/4P3/P1PP4/1P3PPP/RNKNBBRQ w GAga - 1 9 +perft 1 20 +perft 2 596 +perft 3 13091 +perft 4 399069 +perft 5 9416862 +perft 6 293659781 + +id 1 +epd rnknbrqb/p1p1pp1p/3p4/1p1N2p1/8/N7/PPPPPPPP/1RK1BRQB w Ffa - 0 9 +perft 1 26 +perft 2 724 +perft 3 18942 +perft 4 552040 +perft 5 15257204 +perft 6 461293885 + +id 1 +epd rbnknrb1/1p1ppp1p/p1p3p1/8/1P3P2/1R6/PqPPP1PP/RBNKN1BQ w Afa - 0 9 +perft 1 31 +perft 2 1183 +perft 3 34723 +perft 4 1289502 +perft 5 38722152 +perft 6 1421492227 + +id 1 +epd rnkbnrbq/2p1ppp1/p7/1p1p3p/3P4/1P4P1/P1P1PP1P/RNKBNRBQ w FAfa - 0 9 +perft 1 24 +perft 2 506 +perft 3 12748 +perft 4 301464 +perft 5 8086100 +perft 6 207129256 + +id 1 +epd r1knrbbq/pp1ppppp/2p1n3/8/2P3P1/P7/1PKPPP1P/RN1NRBBQ w ea - 0 9 +perft 1 28 +perft 2 570 +perft 3 16037 +perft 4 352471 +perft 5 10278695 +perft 6 242592363 + +id 1 +epd rnknrq1b/ppp1p1p1/4b3/3p1p1p/6P1/P4P2/1PPPPQ1P/RNKNR1BB w EAea - 2 9 +perft 1 30 +perft 2 739 +perft 3 23124 +perft 4 594962 +perft 5 19252739 +perft 6 521629794 + +id 1 +epd bbqr1krn/pppp1p1p/5n2/4p1p1/3P4/P3QP2/1PP1P1PP/BB1RNKRN w GDgd - 0 9 +perft 1 31 +perft 2 799 +perft 3 25627 +perft 4 674913 +perft 5 22172123 +perft 6 609277274 + +id 1 +epd bq1b1krn/pp1ppppp/3n4/2r5/3p3N/6N1/PPP1PPPP/BQRB1KR1 w GCg - 2 9 +perft 1 21 +perft 2 798 +perft 3 18571 +perft 4 688429 +perft 5 17546069 +perft 6 647165916 + +id 1 +epd bqrnkbrn/2pp1pp1/p7/1p2p2p/1P6/4N3/P1PPPPPP/BQR1KBRN w GCgc - 0 9 +perft 1 27 +perft 2 783 +perft 3 22327 +perft 4 670798 +perft 5 20059741 +perft 6 624462073 + +id 1 +epd bqr1krnb/1np1pppp/8/pp1p4/8/2P2N2/PP1PPPPP/BQRNKR1B w FCfc - 0 9 +perft 1 28 +perft 2 636 +perft 3 18874 +perft 4 461104 +perft 5 14237097 +perft 6 372181570 + +id 1 +epd qbb1rkrn/1ppppppp/p7/7n/8/P2P4/1PP1PPPP/QBBRNKRN w Gg - 0 9 +perft 1 25 +perft 2 547 +perft 3 13837 +perft 4 332918 +perft 5 8849383 +perft 6 229112926 + +id 1 +epd 1rbbnkrn/p1p1pp1p/2q5/1p1p2p1/8/2P3P1/PP1PPP1P/QRBBNKRN w GBgb - 2 9 +perft 1 24 +perft 2 1010 +perft 3 24370 +perft 4 983770 +perft 5 24328258 +perft 6 961371180 + +id 1 +epd qrb1kbrn/ppp1p2p/4npp1/3p4/8/1PP4P/PR1PPPP1/Q1BNKBRN w Ggb - 1 9 +perft 1 18 +perft 2 451 +perft 3 9291 +perft 4 247310 +perft 5 5568106 +perft 6 155744022 + +id 1 +epd qr2krnb/p1p1pppp/b1np4/1p6/3NP3/7P/PPPP1PP1/QRBNKR1B w FBfb - 2 9 +perft 1 25 +perft 2 667 +perft 3 17081 +perft 4 476030 +perft 5 12458875 +perft 6 361495148 + +id 1 +epd qbrnbkrn/ppp3pp/3p4/5p2/2P1pP2/6PP/PP1PP3/QBRNBKRN w GCgc - 0 9 +perft 1 24 +perft 2 650 +perft 3 16835 +perft 4 445263 +perft 5 12187382 +perft 6 326834539 + +id 1 +epd qrnb1krn/ppp1p1pp/5p2/2Np4/b2P4/2P5/PP2PPPP/QR1BBKRN w GBgb - 0 9 +perft 1 27 +perft 2 641 +perft 3 17490 +perft 4 432041 +perft 5 12103076 +perft 6 310695797 + +id 1 +epd qrnkbbrn/pp2pp2/8/2pp2pp/6PP/3P4/PPPKPP2/QRN1BBRN w gb - 0 9 +perft 1 22 +perft 2 554 +perft 3 13116 +perft 4 357404 +perft 5 9014737 +perft 6 258925091 + +id 1 +epd qrnkbrnb/p1p1ppp1/1p6/3p4/3P3p/5N1P/PPP1PPP1/QRNKBR1B w FBfb - 0 9 +perft 1 24 +perft 2 529 +perft 3 13205 +perft 4 318722 +perft 5 8295874 +perft 6 213856651 + +id 1 +epd qbr1krbn/1pppp1pp/p7/5pn1/2PP4/8/PPB1PPPP/Q1RNKRBN w FCfc - 0 9 +perft 1 26 +perft 2 831 +perft 3 21651 +perft 4 696830 +perft 5 18961456 +perft 6 621884383 + +id 1 +epd 1rnbkrbn/1qp1pppp/3p4/pp6/4P3/1NP4P/PP1P1PP1/QR1BKRBN w FBfb - 0 9 +perft 1 24 +perft 2 597 +perft 3 15089 +perft 4 404761 +perft 5 10832084 +perft 6 307793179 + +id 1 +epd q1rkrbbn/ppp1pppp/8/3p4/1PnP4/P7/1RP1PPPP/Q1NKRBBN w Ee - 1 9 +perft 1 20 +perft 2 520 +perft 3 10769 +perft 4 278067 +perft 5 6452205 +perft 6 170268300 + +id 1 +epd qrnkrn1b/ppppp1pp/4b3/7P/6p1/P7/1PPPPP2/QRNKRNBB w EBeb - 0 9 +perft 1 26 +perft 2 566 +perft 3 15623 +perft 4 381312 +perft 5 10940750 +perft 6 287987207 + +id 1 +epd bbr1nkrn/ppp1pppp/3q4/3p4/8/P7/1PPPPPPP/BBRQNRKN w gc - 5 9 +perft 1 19 +perft 2 661 +perft 3 13895 +perft 4 460396 +perft 5 10870247 +perft 6 356399665 + +id 1 +epd brqbnkrn/pp1pp2p/5pp1/2p5/4P3/P2P1N2/1PP2PPP/BRQB1KRN w GBgb - 0 9 +perft 1 27 +perft 2 679 +perft 3 19916 +perft 4 527306 +perft 5 16391730 +perft 6 455940859 + +id 1 +epd 2qnkbrn/p1pppppp/8/1r6/1p2bP2/7N/PPPPP1PP/BR1QKBRN w GBg - 4 9 +perft 1 18 +perft 2 774 +perft 3 15713 +perft 4 635461 +perft 5 14371755 +perft 6 559579332 + +id 1 +epd r1qnkr1b/p1pppppp/7n/1p6/8/1P3b1N/PRPPPPPP/B1QNK1RB w f - 5 9 +perft 1 21 +perft 2 677 +perft 3 15437 +perft 4 501520 +perft 5 12463801 +perft 6 410795298 + +id 1 +epd rbbqn1rn/pppp1pp1/3k4/4p2Q/2PPP3/8/PP3PPP/RBB1NKRN w GA - 1 9 +perft 1 40 +perft 2 742 +perft 3 28757 +perft 4 579833 +perft 5 21852196 +perft 6 471452088 + +id 1 +epd rqbbnkrn/3pppp1/p1p4p/1p6/5P2/P2N4/1PPPP1PP/RQBBK1RN w ga - 0 9 +perft 1 23 +perft 2 665 +perft 3 16400 +perft 4 492544 +perft 5 12794736 +perft 6 396640086 + +id 1 +epd r2nkbrn/pp2pppp/8/2ppqb2/2P3P1/5P2/PP1PPN1P/RQB1KBRN w GAga - 3 9 +perft 1 28 +perft 2 1108 +perft 3 31164 +perft 4 1194581 +perft 5 34780853 +perft 6 1292405738 + +id 1 +epd rqbnk1nb/p1pppr1p/5p2/1p4p1/1PP1P3/8/P2P1PPP/RQBNKRNB w FAa - 1 9 +perft 1 26 +perft 2 650 +perft 3 18208 +perft 4 491403 +perft 5 14565370 +perft 6 416833400 + +id 1 +epd rbqnb1rn/p1pp1kpp/1p2pp2/8/4P2P/P5P1/1PPP1P2/RBQNBKRN w GA - 0 9 +perft 1 20 +perft 2 437 +perft 3 9423 +perft 4 222154 +perft 5 5282124 +perft 6 132309824 + +id 1 +epd rqnbbkrn/p1p1pppp/3p4/1p5B/8/1P1NP3/P1PP1PPP/RQ2BKRN w GAga - 0 9 +perft 1 30 +perft 2 606 +perft 3 18382 +perft 4 422491 +perft 5 12989786 +perft 6 326601372 + +id 1 +epd rqnkbbr1/ppppp1pp/5p2/7n/8/2PNP2P/PP1P1PP1/RQ1KBBRN w GAga - 1 9 +perft 1 23 +perft 2 482 +perft 3 12506 +perft 4 297869 +perft 5 8430874 +perft 6 217797292 + +id 1 +epd r1nkbrnb/2ppppp1/1q6/pp5p/1P6/P3P3/2PPKPPP/RQN1BRNB w fa - 2 9 +perft 1 25 +perft 2 827 +perft 3 21518 +perft 4 701071 +perft 5 19290675 +perft 6 632892337 + +id 1 +epd rbqnkrbn/p1ppppp1/7p/1p6/7P/2N1P3/PPPP1PPB/RBQ1KR1N w FAfa - 1 9 +perft 1 30 +perft 2 627 +perft 3 18566 +perft 4 440217 +perft 5 12976682 +perft 6 337377291 + +id 1 +epd r1nbkrbn/p1qp1ppp/8/1pp1p3/2P1P3/6P1/PP1PBP1P/RQN1KRBN w FAfa - 2 9 +perft 1 22 +perft 2 616 +perft 3 14503 +perft 4 431199 +perft 5 10850952 +perft 6 335943324 + +id 1 +epd rqnkr1bn/ppp1ppb1/3p2pp/8/P7/2P2P2/1PKPP1PP/RQN1RBBN w ea - 1 9 +perft 1 31 +perft 2 679 +perft 3 21365 +perft 4 493500 +perft 5 15661072 +perft 6 379844460 + +id 1 +epd r2krnbb/qppp1ppp/1n6/p3p3/PP6/4N3/N1PPPPPP/RQ1KR1BB w EAea - 4 9 +perft 1 24 +perft 2 645 +perft 3 17054 +perft 4 487028 +perft 5 13837270 +perft 6 416239106 + +id 1 +epd bbr1qk1n/1ppppp1p/2n5/p7/P7/1P2P3/2PP1PrP/1BRNQKRN w GCc - 0 9 +perft 1 18 +perft 2 520 +perft 3 10680 +perft 4 304462 +perft 5 7215306 +perft 6 207612575 + +id 1 +epd brnbq1rn/2ppppkp/p5p1/1p6/8/1BP3P1/PP1PPP1P/BRN1QRKN w - - 0 9 +perft 1 21 +perft 2 625 +perft 3 13989 +perft 4 419667 +perft 5 9929336 +perft 6 300902534 + +id 1 +epd brn1kbrn/pp2p1pp/3p4/q1p2p2/2P4P/6P1/PP1PPP2/BRNQKBRN w GBgb - 1 9 +perft 1 18 +perft 2 477 +perft 3 10205 +perft 4 273925 +perft 5 6720181 +perft 6 187205941 + +id 1 +epd brn1krnb/p3pppp/1qpp4/1p6/2P3P1/1P6/P2PPP1P/BRNQKRNB w FBfb - 1 9 +perft 1 30 +perft 2 835 +perft 3 24761 +perft 4 716151 +perft 5 21806428 +perft 6 654487872 + +id 1 +epd r1b1qkrn/1p1ppppp/p1p1n3/8/4P3/1PN5/P1PPQPPb/RBB2KRN w GAga - 0 9 +perft 1 28 +perft 2 825 +perft 3 24536 +perft 4 716585 +perft 5 22079005 +perft 6 647939781 + +id 1 +epd r1bbqk1n/p1pppprp/n7/1p4p1/5P2/2N3N1/PPPPP1PP/1RBBQKR1 w Ga - 4 9 +perft 1 25 +perft 2 545 +perft 3 14657 +perft 4 358854 +perft 5 10271111 +perft 6 273864588 + +id 1 +epd rnbqkbrn/p1pp1pp1/4p3/7p/2p4P/2P5/PP1PPPP1/R1BQKBRN w GAga - 0 9 +perft 1 17 +perft 2 445 +perft 3 9076 +perft 4 255098 +perft 5 5918310 +perft 6 174733195 + +id 1 +epd rnbqkrnb/1p1pp1p1/2p4p/p4p2/3P2P1/7N/PPPBPP1P/RN1QKR1B w FAfa - 0 9 +perft 1 34 +perft 2 746 +perft 3 25319 +perft 4 623133 +perft 5 21285553 +perft 6 569141201 + +id 1 +epd rbnqbkr1/1ppppp2/p5n1/6pp/4P3/1N6/PPPP1PPP/RBQ1BRKN w ga - 2 9 +perft 1 18 +perft 2 466 +perft 3 9683 +perft 4 260864 +perft 5 6051500 +perft 6 170135726 + +id 1 +epd rnqb1krn/ppppp1p1/7p/7b/P1P2pPP/8/1P1PPP2/RNQBBKRN w GAga - 0 9 +perft 1 24 +perft 2 575 +perft 3 15400 +perft 4 385825 +perft 5 11039042 +perft 6 291243811 + +id 1 +epd rnqkbbr1/p1pp1ppp/4p3/1p6/P3P2n/5P2/1PPP1NPP/RNQKBBR1 w GAga - 2 9 +perft 1 27 +perft 2 803 +perft 3 22883 +perft 4 694449 +perft 5 20666099 +perft 6 638696065 + +id 1 +epd rn1kbrnb/1qppp1pp/1p6/p4p2/1B1P4/1P5N/P1P1PPPP/RNQK1R1B w FAfa - 0 9 +perft 1 37 +perft 2 1209 +perft 3 43015 +perft 4 1425600 +perft 5 49748034 +perft 6 1671593862 + +id 1 +epd rbnqkrbn/Bppp1p2/p5pp/4p3/5P2/6PP/PPPPP3/RBNQKR1N w FAfa - 0 9 +perft 1 29 +perft 2 720 +perft 3 20434 +perft 4 534148 +perft 5 15384362 +perft 6 421343249 + +id 1 +epd rnqbkr1n/1p1ppbpp/3p1p2/p7/8/1P6/P1PPPPPP/R1QBKRBN w FAfa - 0 9 +perft 1 20 +perft 2 657 +perft 3 14424 +perft 4 492678 +perft 5 11843134 +perft 6 413965054 + +id 1 +epd rnqkrb1n/ppppp3/6p1/5p1p/2b2P2/P1N5/1PPPP1PP/RQ1KRBBN w EAea - 1 9 +perft 1 28 +perft 2 749 +perft 3 20684 +perft 4 543151 +perft 5 15379233 +perft 6 417191461 + +id 1 +epd rnqk1nbb/1pp2ppp/3pr3/p3p3/3P1P2/2N3N1/PPP1P1PP/R1QKR1BB w EAa - 1 9 +perft 1 29 +perft 2 883 +perft 3 26412 +perft 4 815098 +perft 5 25144295 +perft 6 789705382 + +id 1 +epd bbr1kqrn/p1p1ppp1/1p2n2p/3p4/1P1P4/2N5/P1P1PPPP/BBR1KQRN w GCgc - 0 9 +perft 1 22 +perft 2 485 +perft 3 11475 +perft 4 271271 +perft 5 6825123 +perft 6 171793012 + +id 1 +epd brnbkq1n/ppp1ppr1/7p/3p2p1/2P3PP/8/PPBPPP2/BRN1KQRN w GBb - 2 9 +perft 1 30 +perft 2 634 +perft 3 19017 +perft 4 442537 +perft 5 13674310 +perft 6 345386924 + +id 1 +epd brnkqbr1/1pppp1pp/5p2/p7/P1P1P2n/8/1P1P1PP1/BRNKQBRN w GBgb - 0 9 +perft 1 21 +perft 2 504 +perft 3 11672 +perft 4 305184 +perft 5 7778289 +perft 6 217596497 + +id 1 +epd b1rkqrnb/p1ppp1pp/1p1n4/5p2/5P2/PN5P/1PPPP1P1/BR1KQRNB w FBf - 0 9 +perft 1 23 +perft 2 688 +perft 3 17259 +perft 4 531592 +perft 5 14228372 +perft 6 451842354 + +id 1 +epd 1bbnkqrn/rppppp2/p5p1/7p/7P/P1P1P3/1P1P1PP1/RBBNKQRN w GAg - 1 9 +perft 1 25 +perft 2 450 +perft 3 12391 +perft 4 263946 +perft 5 7752404 +perft 6 185393913 + +id 1 +epd rnbbkqr1/1pppppp1/7p/p3n3/PP5P/8/1BPPPPP1/RN1BKQRN w GAga - 0 9 +perft 1 23 +perft 2 543 +perft 3 12224 +perft 4 305812 +perft 5 7549008 +perft 6 199883770 + +id 1 +epd r1bkqbrn/ppppp1pp/8/5p2/3nPP2/1P4N1/P1PP2PP/RNBKQBR1 w GAga - 1 9 +perft 1 27 +perft 2 751 +perft 3 21158 +perft 4 600417 +perft 5 17989920 +perft 6 527273615 + +id 1 +epd rnbkqr1b/1p1pp1pp/p4p1n/2p5/1P5P/N4P2/P1PPP1P1/R1BKQRNB w FAfa - 0 9 +perft 1 21 +perft 2 498 +perft 3 11738 +perft 4 302278 +perft 5 7808375 +perft 6 216224115 + +id 1 +epd rbnkbqrn/p1p3pp/1p1p4/B3pp2/3P2P1/6N1/PPP1PP1P/RBNK1QR1 w GAga - 0 9 +perft 1 34 +perft 2 977 +perft 3 33464 +perft 4 961128 +perft 5 33318567 +perft 6 978991050 + +id 1 +epd r1kbbqrn/ppp3pp/2np1p2/1P2p3/3P1P2/8/P1P1P1PP/RNKBBQRN w GAga - 0 9 +perft 1 32 +perft 2 920 +perft 3 28916 +perft 4 844881 +perft 5 26763259 +perft 6 797524786 + +id 1 +epd rk1qbbrn/p2npppp/1p6/2p4Q/8/4P3/PPPP1PPP/RNK1B1RN w GA - 2 9 +perft 1 35 +perft 2 657 +perft 3 22359 +perft 4 495406 +perft 5 16662477 +perft 6 419496845 + +id 1 +epd rnk1brnb/pp1p1pp1/8/q1p1p2p/5P2/NP6/P1PPP1PP/R1KQBRNB w FAfa - 1 9 +perft 1 26 +perft 2 774 +perft 3 20215 +perft 4 610661 +perft 5 16987110 +perft 6 523437649 + +id 1 +epd rb1kqrbn/npp1ppp1/p7/3P3p/2PP4/8/PP3PPP/RBNKQRBN w FAfa - 0 9 +perft 1 35 +perft 2 775 +perft 3 27395 +perft 4 661118 +perft 5 23983464 +perft 6 625669222 + +id 1 +epd rnkb1rbn/pp1p2pp/8/2p1pp1q/P6P/1PN5/2PPPPP1/R1KBQRBN w FAfa - 1 9 +perft 1 22 +perft 2 899 +perft 3 21188 +perft 4 850597 +perft 5 21518343 +perft 6 857951339 + +id 1 +epd rnkqrbbn/1pppp1p1/8/p2N1p1p/2P4P/8/PP1PPPP1/R1KQRBBN w EAea - 0 9 +perft 1 29 +perft 2 585 +perft 3 17571 +perft 4 393221 +perft 5 12238776 +perft 6 299752383 + +id 1 +epd rnk1r1bb/pp1ppppp/1q4n1/2p5/5P1P/3PP3/PPP3P1/RNKQRNBB w EAea - 1 9 +perft 1 27 +perft 2 884 +perft 3 24613 +perft 4 811915 +perft 5 23698701 +perft 6 790239502 + +id 1 +epd bbrnkrqn/1ppp1p2/6pp/p3p3/5PP1/2PB4/PP1PP2P/B1RNKRQN w FCfc - 0 9 +perft 1 37 +perft 2 693 +perft 3 25425 +perft 4 550527 +perft 5 20138432 +perft 6 481498664 + +id 1 +epd b1rbkrqn/ppp2ppp/1n2p3/3p4/6P1/2PP4/PP2PP1P/BRNBKRQN w FBf - 1 9 +perft 1 21 +perft 2 463 +perft 3 10610 +perft 4 253204 +perft 5 6307276 +perft 6 159025909 + +id 1 +epd brnkrb1n/1pp1p1pp/3p4/p1Nq1p2/2P5/8/PP1PPPPP/BRK1RBQN w eb - 2 9 +perft 1 27 +perft 2 725 +perft 3 17842 +perft 4 496072 +perft 5 12604078 +perft 6 362747791 + +id 1 +epd brn1r1nb/ppppkppp/4p3/8/2PP1P2/8/PP1KP1PP/BRN1RQNB w - - 1 9 +perft 1 25 +perft 2 623 +perft 3 16874 +perft 4 426659 +perft 5 12290985 +perft 6 317097424 + +id 1 +epd rbb1krqn/1pp1pp1p/p3n1p1/3pP3/8/1PN5/P1PP1PPP/RBB1KRQN w FAfa d6 0 9 +perft 1 23 +perft 2 529 +perft 3 12641 +perft 4 310277 +perft 5 7861413 +perft 6 202594556 + +id 1 +epd r1bbkrqn/p1pppppp/8/4n3/1p5P/P2P2P1/1PP1PP2/RNBBKRQN w FAfa - 0 9 +perft 1 23 +perft 2 571 +perft 3 13133 +perft 4 346793 +perft 5 8699448 +perft 6 243460643 + +id 1 +epd rnbkrbqn/p1pp1ppp/4p3/1p6/8/BPN3P1/P1PPPP1P/R2KRBQN w EAea - 2 9 +perft 1 29 +perft 2 692 +perft 3 20014 +perft 4 500375 +perft 5 14904192 +perft 6 386694739 + +id 1 +epd rnbkrqn1/pppppp2/8/1Q2b1pp/P3P3/5P2/1PPP2PP/RNBKR1NB w EAea - 0 9 +perft 1 37 +perft 2 1001 +perft 3 36440 +perft 4 987842 +perft 5 35626426 +perft 6 993747544 + +id 1 +epd rbnkbrqn/p1pppp2/7p/1p4pP/3P1P2/8/PPP1P1P1/RBNKBRQN w FAfa - 0 9 +perft 1 30 +perft 2 564 +perft 3 17143 +perft 4 381364 +perft 5 11859538 +perft 6 293703269 + +id 1 +epd 1nkbbrqn/3ppppp/r1p5/pp6/8/4PP2/PPPPN1PP/RNKBBRQ1 w FAf - 2 9 +perft 1 26 +perft 2 546 +perft 3 14641 +perft 4 344592 +perft 5 9556962 +perft 6 245137199 + +id 1 +epd rnkrbbq1/pppppnp1/7p/8/1B1Q1p2/3P1P2/PPP1P1PP/RNKR1B1N w DAda - 2 9 +perft 1 43 +perft 2 887 +perft 3 36240 +perft 4 846858 +perft 5 33185346 +perft 6 851927292 + +id 1 +epd 1rkrbqnb/pppppp2/2n3p1/7p/3P3P/P4N2/1PP1PPP1/RNKRBQ1B w DAd - 0 9 +perft 1 26 +perft 2 622 +perft 3 16049 +perft 4 403921 +perft 5 10786140 +perft 6 285233838 + +id 1 +epd rbnkr1bn/pp1pqp1p/2p1p3/6p1/3P4/7P/PPP1PPP1/RBNKRQBN w EAea - 0 9 +perft 1 19 +perft 2 566 +perft 3 12257 +perft 4 381197 +perft 5 9107175 +perft 6 293397389 + +id 1 +epd r1kbrqb1/pppp2pp/2n1p1n1/5p1B/4PP2/P7/1PPP2PP/RNK1RQBN w EAea - 2 9 +perft 1 39 +perft 2 1359 +perft 3 53626 +perft 4 1876028 +perft 5 73871486 +perft 6 2633945690 + +id 1 +epd rnkrqbbn/p1p3pp/1p1ppp2/8/1P6/3P2P1/PKP1PP1P/RN1RQBBN w da - 0 9 +perft 1 26 +perft 2 776 +perft 3 20735 +perft 4 611907 +perft 5 16884013 +perft 6 503561996 + +id 1 +epd rnkrqnbb/ppp2p1p/3p4/4p1p1/3P3P/N1Q5/PPP1PPP1/R1KR1NBB w DAda - 0 9 +perft 1 40 +perft 2 1175 +perft 3 45637 +perft 4 1375884 +perft 5 52620163 +perft 6 1633655838 + +id 1 +epd bbrnkrn1/p1pppp2/1p6/6pp/3q4/1P3QP1/P1PPPP1P/BBRNKRN1 w FCfc - 0 9 +perft 1 34 +perft 2 1398 +perft 3 45749 +perft 4 1712950 +perft 5 57268492 +perft 6 2059942014 + +id 1 +epd br1bkrnq/1p2pppp/pnp5/3p4/P1P5/5P2/1P1PPKPP/BRNB1RNQ w fb - 2 9 +perft 1 24 +perft 2 501 +perft 3 12237 +perft 4 284936 +perft 5 7049659 +perft 6 177940764 + +id 1 +epd brnkrbn1/pppppp1q/B6p/6p1/8/1P2PP2/P1PP2PP/BRNKR1NQ w EBeb - 0 9 +perft 1 34 +perft 2 815 +perft 3 25868 +perft 4 700970 +perft 5 22006883 +perft 6 639803952 + +id 1 +epd br1krnqb/pppppp1p/1n4p1/8/8/P2NN3/2PPPPPP/BR1K1RQB w Beb - 2 9 +perft 1 37 +perft 2 1029 +perft 3 36748 +perft 4 1025712 +perft 5 36214583 +perft 6 1026195877 + +id 1 +epd rbbnkr1q/p1p2ppp/1p1ppn2/8/1PP4P/8/P2PPPP1/RBBNKRNQ w FAfa - 0 9 +perft 1 28 +perft 2 755 +perft 3 22623 +perft 4 605106 +perft 5 18972778 +perft 6 513486101 + +id 1 +epd r1b1krnq/pp2pppp/1bn5/2pp4/4N3/5P2/PPPPPRPP/R1BBK1NQ w Afa - 0 9 +perft 1 24 +perft 2 705 +perft 3 17427 +perft 4 532521 +perft 5 13532966 +perft 6 426443376 + +id 1 +epd 1nbkrbn1/rpppppqp/p7/6p1/4P3/3P2P1/PPP1KP1P/RNB1RBNQ w e - 1 9 +perft 1 31 +perft 2 800 +perft 3 24748 +perft 4 693366 +perft 5 21193292 +perft 6 625757852 + +id 1 +epd r1bkrnqb/pp3ppp/n1ppp3/8/1P5P/P7/R1PPPPP1/1NBKRNQB w Eea - 0 9 +perft 1 21 +perft 2 482 +perft 3 11417 +perft 4 275339 +perft 5 7112890 +perft 6 180378139 + +id 1 +epd rbnkbrnq/ppp1p2p/5p2/3p2p1/1B1P4/1N4P1/PPP1PP1P/RB1K1RNQ w FAfa - 0 9 +perft 1 33 +perft 2 780 +perft 3 25532 +perft 4 628945 +perft 5 20756770 +perft 6 535497008 + +id 1 +epd rnk1brnq/pp1ppppp/2p5/b7/8/1P2P2P/P1PP1PPQ/RNKBBRN1 w FAfa - 3 9 +perft 1 29 +perft 2 648 +perft 3 19043 +perft 4 449637 +perft 5 13722785 +perft 6 341389148 + +id 1 +epd rnkrbbnq/p1p3pp/5p2/1p1pp3/P7/1PN2P2/2PPP1PP/R1KRBBNQ w DAda - 0 9 +perft 1 26 +perft 2 827 +perft 3 21865 +perft 4 683167 +perft 5 18916370 +perft 6 589161126 + +id 1 +epd r1krbnqb/p1pp1ppp/2n1p3/8/1p4P1/PPP5/3PPP1P/RNKRBNQB w DAda - 1 9 +perft 1 25 +perft 2 540 +perft 3 14709 +perft 4 331332 +perft 5 9491817 +perft 6 225389422 + +id 1 +epd rbnkrnbq/ppp1pp2/3p2p1/2N5/P6p/2P5/1P1PPPPP/RB1KRNBQ w EAea - 0 9 +perft 1 32 +perft 2 790 +perft 3 25107 +perft 4 661207 +perft 5 20906017 +perft 6 578332225 + +id 1 +epd rnkbrn1q/1ppppppb/8/p4N1p/8/P1N5/1PPPPPPP/R1KBR1BQ w EAea - 0 9 +perft 1 31 +perft 2 691 +perft 3 20813 +perft 4 510665 +perft 5 15308408 +perft 6 404129987 + +id 1 +epd rnkrnbbq/p1p2ppp/3pp3/1p6/6P1/4PQ1B/PPPP1P1P/RNKRN1B1 w DAda - 0 9 +perft 1 29 +perft 2 558 +perft 3 16800 +perft 4 352887 +perft 5 10825379 +perft 6 246965507 + +id 1 +epd rnkrnqbb/pp2p1p1/3p3p/2p2p2/5P2/1P1N4/P1PPPQPP/RNKR2BB w DAda - 0 9 +perft 1 29 +perft 2 762 +perft 3 23210 +perft 4 644936 +perft 5 20522675 +perft 6 596067005 + +id 1 +epd bb1rknnr/ppqppppp/8/2p5/3P1N2/1P6/P1P1PPPP/BBQRKN1R w HDhd - 1 9 +perft 1 33 +perft 2 963 +perft 3 32279 +perft 4 1000890 +perft 5 34552118 +perft 6 1124738493 + +id 1 +epd bqrbknnr/ppp1p2p/8/3p1p2/5p2/P3N2P/1PPPP1P1/BQRBK1NR w HChc - 0 9 +perft 1 20 +perft 2 398 +perft 3 9009 +perft 4 194859 +perft 5 4834319 +perft 6 113660536 + +id 1 +epd b1rk1bnr/qpp1pppp/p4n2/3p4/3PPP2/7N/PPP3PP/BQRKNB1R w HChc - 1 9 +perft 1 25 +perft 2 648 +perft 3 16587 +perft 4 455720 +perft 5 12200870 +perft 6 351766307 + +id 1 +epd bqkrnnrb/pppp2p1/4pp2/4P2p/6P1/7P/PPPP1P2/BQRKNNRB w GC - 1 9 +perft 1 30 +perft 2 493 +perft 3 15118 +perft 4 280726 +perft 5 8786998 +perft 6 181492621 + +id 1 +epd q1brknnr/1p1ppppp/p7/2p5/8/1PPP4/P2RPPPP/QBB1KNNR w Hhd - 0 9 +perft 1 25 +perft 2 501 +perft 3 13206 +perft 4 290463 +perft 5 7982978 +perft 6 192717198 + +id 1 +epd qrb1k1nr/ppppb1pp/6n1/4ppN1/3P4/4N3/PPP1PPPP/QRBBK2R w HBhb - 2 9 +perft 1 31 +perft 2 872 +perft 3 26191 +perft 4 739276 +perft 5 22493014 +perft 6 646855304 + +id 1 +epd 1rbknbnr/1ppp1pp1/q6p/p3p3/5P2/2PPB3/PP2P1PP/QR1KNBNR w HBhb - 0 9 +perft 1 28 +perft 2 1020 +perft 3 28147 +perft 4 984000 +perft 5 27484692 +perft 6 947786800 + +id 1 +epd qrbk2rb/1ppp1ppp/5nn1/p3p3/1N6/P7/1PPPPPPP/QRB1KNRB w gb - 0 9 +perft 1 23 +perft 2 592 +perft 3 14398 +perft 4 395716 +perft 5 10098215 +perft 6 293988585 + +id 1 +epd qbrk1nnr/1pp1pppp/2b5/p2p4/P2P2P1/8/1PP1PP1P/QBKRBNNR w hc - 1 9 +perft 1 26 +perft 2 654 +perft 3 18103 +perft 4 471653 +perft 5 13740891 +perft 6 373081138 + +id 1 +epd qrkbbnnr/ppp2p1p/4p3/3p2p1/P7/2PP4/1P2PPPP/QRKBBNNR w HBhb - 0 9 +perft 1 25 +perft 2 626 +perft 3 16616 +perft 4 431634 +perft 5 12079406 +perft 6 324006164 + +id 1 +epd qr1kbbnr/ppp1pp1p/4n1p1/2Pp4/6P1/4N3/PP1PPP1P/QRK1BBNR w HB d6 0 9 +perft 1 26 +perft 2 699 +perft 3 18068 +perft 4 497152 +perft 5 13353359 +perft 6 375702908 + +id 1 +epd qrk1b1rb/p1pppppp/3nnQ2/1p6/1P3P2/3P4/P1P1P1PP/1RKNBNRB w GBgb - 3 9 +perft 1 43 +perft 2 1369 +perft 3 55463 +perft 4 1831200 +perft 5 71514365 +perft 6 2427477375 + +id 1 +epd qbrk1nbr/pppp3p/5n2/4ppp1/3P1P2/4N3/PPP1P1PP/QBKRN1BR w hc - 0 9 +perft 1 25 +perft 2 752 +perft 3 20165 +perft 4 615263 +perft 5 17493373 +perft 6 543180234 + +id 1 +epd qrkb1nbr/1pppppQp/3n4/p7/5p2/1P1N4/P1PPP1PP/1RKB1NBR w HBhb - 0 9 +perft 1 45 +perft 2 946 +perft 3 40100 +perft 4 966903 +perft 5 39736157 +perft 6 1051910977 + +id 1 +epd qrk1nbbr/ppp1p1p1/4n2p/3p1p2/1P5P/3P2P1/P1P1PP2/QRKNNBBR w HBhb - 1 9 +perft 1 32 +perft 2 770 +perft 3 25367 +perft 4 646977 +perft 5 21717615 +perft 6 577979364 + +id 1 +epd qrkn1rbb/pp2pppp/2p5/3p4/P2Qn1P1/1P6/2PPPP1P/1RKNNRBB w FBfb - 0 9 +perft 1 38 +perft 2 943 +perft 3 35335 +perft 4 868165 +perft 5 31909835 +perft 6 798405123 + +id 1 +epd bbrqknnr/ppp4p/3pp3/5pp1/4PP2/5Q2/PPPP2PP/BBR1KNNR w HChc - 0 9 +perft 1 36 +perft 2 843 +perft 3 29974 +perft 4 758528 +perft 5 26828059 +perft 6 723306114 + +id 1 +epd 1rqbkn1r/p1p1pppp/1p5n/P2p4/3Pb1P1/8/1PP1PP1P/BRQBKNNR w HBhb - 0 9 +perft 1 23 +perft 2 778 +perft 3 19482 +perft 4 649789 +perft 5 17337683 +perft 6 579112676 + +id 1 +epd br1knbnr/1qp1pppp/pp1p4/8/8/PP6/2PPPPPP/BRQKNBNR w HBhb - 2 9 +perft 1 26 +perft 2 697 +perft 3 18835 +perft 4 546622 +perft 5 15280079 +perft 6 473071890 + +id 1 +epd brqk2rb/ppppp1pp/4np2/8/2n5/3P1Q2/PP2PPPP/BR1KNNRB w GBgb - 0 9 +perft 1 32 +perft 2 948 +perft 3 30434 +perft 4 885713 +perft 5 29821322 +perft 6 874251866 + +id 1 +epd r1bqknnr/pp1pp1p1/5p1p/2p1b2N/2P5/8/PPQPPPPP/RBB1K1NR w HAha - 0 9 +perft 1 31 +perft 2 785 +perft 3 25549 +perft 4 659952 +perft 5 22244193 +perft 6 592797491 + +id 1 +epd rqbbknnr/ppppp2p/5pp1/8/8/1P3PP1/PQPPP2P/R1BBKNNR w HAha - 0 9 +perft 1 23 +perft 2 391 +perft 3 10163 +perft 4 198450 +perft 5 5576671 +perft 6 121267576 + +id 1 +epd rqbknbnr/1pp1p2p/p7/3p1pp1/7N/1PP5/P2PPPPP/RQBK1BNR w HAha - 0 9 +perft 1 27 +perft 2 676 +perft 3 19606 +perft 4 522428 +perft 5 15955388 +perft 6 448477218 + +id 1 +epd rqb1nnrb/2ppkppp/1p2p3/p7/2PPP3/1P6/P4PPP/RQBKNNRB w GA - 1 9 +perft 1 31 +perft 2 727 +perft 3 22895 +perft 4 570647 +perft 5 18361051 +perft 6 483248153 + +id 1 +epd rb1kbn1r/p1ppppp1/qp5n/7p/P7/RPP5/3PPPPP/1BQKBNNR w Hha - 2 9 +perft 1 29 +perft 2 837 +perft 3 23815 +perft 4 730083 +perft 5 21279560 +perft 6 682863811 + +id 1 +epd rqkbb1nr/p1p2ppp/1p1p2n1/3Np3/4P3/5N2/PPPP1PPP/RQKBB2R w HAha - 0 9 +perft 1 28 +perft 2 717 +perft 3 20663 +perft 4 550987 +perft 5 16347343 +perft 6 453153783 + +id 1 +epd rqknbbr1/p1pppp1p/1p3np1/8/4P3/2P2P1P/PP1P2P1/RQKNBBNR w HAa - 0 9 +perft 1 27 +perft 2 650 +perft 3 18231 +perft 4 475303 +perft 5 13847463 +perft 6 383256006 + +id 1 +epd r1k1bnrb/1qpppppp/1p2n3/p7/1P5P/6P1/P1PPPP2/RQKNBNR1 w GAga - 1 9 +perft 1 24 +perft 2 806 +perft 3 20693 +perft 4 713220 +perft 5 19382263 +perft 6 686009788 + +id 1 +epd rb1knnbr/1pp1ppp1/p2p3p/5q2/3B2P1/3P1P2/PPP1P2P/RBQKNN1R w HAha - 0 9 +perft 1 34 +perft 2 1360 +perft 3 44096 +perft 4 1605706 +perft 5 51973672 +perft 6 1837704407 + +id 1 +epd rqkb1nbr/p1p1ppp1/1p3n1p/2Qp4/8/2P5/PP1PPPPP/R1KBNNBR w HAha - 2 9 +perft 1 39 +perft 2 983 +perft 3 38218 +perft 4 940989 +perft 5 36347815 +perft 6 918801645 + +id 1 +epd rqknnbbr/2pppp2/pp5p/6p1/1P1P4/4PP2/P1P3PP/RQKNNBBR w HAha - 0 9 +perft 1 26 +perft 2 628 +perft 3 17638 +perft 4 464924 +perft 5 13787303 +perft 6 386125234 + +id 1 +epd rqkn1rbb/1pp1pppp/p7/3p4/3Pn3/2P1PP2/PP4PP/RQKNNRBB w FAfa - 1 9 +perft 1 20 +perft 2 527 +perft 3 12216 +perft 4 321533 +perft 5 8082183 +perft 6 219311659 + +id 1 +epd bbrkqn1r/1pppppp1/5n2/p7/1PP2P1p/7N/P2PP1PP/BBRKQN1R w HChc - 1 9 +perft 1 36 +perft 2 963 +perft 3 35291 +perft 4 973839 +perft 5 35907489 +perft 6 1034223364 + +id 1 +epd brkbqn1r/p2ppppp/7n/1p6/P1p3PP/8/1PPPPP1N/BRKBQ1NR w HBhb - 0 9 +perft 1 18 +perft 2 583 +perft 3 11790 +perft 4 394603 +perft 5 8858385 +perft 6 304339862 + +id 1 +epd brkq1bnr/pp1ppp1p/8/2p2np1/P7/8/1PPPPPPP/BRKQNBNR w HBhb - 0 9 +perft 1 19 +perft 2 552 +perft 3 11811 +perft 4 354260 +perft 5 8432183 +perft 6 262293169 + +id 1 +epd brkqnnrb/1ppppppp/8/8/p3P3/5N2/PPPP1PPP/BRKQ1NRB w GBgb - 3 9 +perft 1 21 +perft 2 397 +perft 3 9653 +perft 4 204350 +perft 5 5489836 +perft 6 128389738 + +id 1 +epd rbbkq1nr/1p2pppp/p1p3nB/3p4/1Q1P4/6N1/PPP1PPPP/RB1K2NR w HAha - 0 9 +perft 1 40 +perft 2 1132 +perft 3 43404 +perft 4 1260470 +perft 5 47425783 +perft 6 1415578783 + +id 1 +epd rkbbq1nr/1pppp1p1/4np2/p6p/8/PP3P2/1KPPP1PP/R1BBQNNR w ha - 0 9 +perft 1 24 +perft 2 596 +perft 3 15220 +perft 4 402121 +perft 5 10822049 +perft 6 302056813 + +id 1 +epd r1bqn1nr/pkpppp1p/1p4pb/8/PN6/R7/1PPPPPPP/1KBQ1BNR w H - 2 9 +perft 1 33 +perft 2 794 +perft 3 25450 +perft 4 649150 +perft 5 20919309 +perft 6 561073410 + +id 1 +epd rkb1nnrb/1pppq1pp/p4p2/4p3/5P2/1P1PB3/P1P1P1PP/RK1QNNRB w GAga - 0 9 +perft 1 26 +perft 2 625 +perft 3 17050 +perft 4 442036 +perft 5 12515042 +perft 6 342967558 + +id 1 +epd rbkqbn1r/pppp1p1p/2n1p1p1/8/8/1P1PP1N1/P1P2PPP/RBKQB1NR w HAha - 1 9 +perft 1 30 +perft 2 660 +perft 3 20308 +perft 4 492714 +perft 5 15348335 +perft 6 403323883 + +id 1 +epd rkqbb1n1/pppppppr/8/6np/5P2/8/PPPPP1PP/RKQBBNNR w HAa - 6 9 +perft 1 23 +perft 2 500 +perft 3 12154 +perft 4 292936 +perft 5 7519117 +perft 6 196524441 + +id 1 +epd rkqnbbnr/ppppppp1/8/7p/3N4/6PP/PPPPPP2/RKQNBB1R w HAa - 0 9 +perft 1 24 +perft 2 484 +perft 3 12495 +perft 4 284570 +perft 5 7775173 +perft 6 193947530 + +id 1 +epd rkqnb1rb/p1p1pppp/1p1p4/2n5/3P4/2P1N1N1/PP2PPPP/RKQ1B1RB w GAga - 0 9 +perft 1 28 +perft 2 1020 +perft 3 29124 +perft 4 1027904 +perft 5 30515456 +perft 6 1073711823 + +id 1 +epd rbk1nnbr/1ppq1ppp/p2p4/4p3/P3B2P/2P5/1P1PPPP1/R1KQNNBR w HAha - 2 9 +perft 1 38 +perft 2 998 +perft 3 37265 +perft 4 1047592 +perft 5 38552638 +perft 6 1139322479 + +id 1 +epd r1qbn1br/k1pppppp/6n1/pp6/5P1P/P7/1PPPP1PB/RKQBNN1R w HA - 1 9 +perft 1 22 +perft 2 549 +perft 3 12867 +perft 4 348574 +perft 5 8725809 +perft 6 251613569 + +id 1 +epd rkqnn1br/pppp3p/4p1pb/5p2/P2P4/7P/1PP1PPPB/RKQNNB1R w HAha - 1 9 +perft 1 32 +perft 2 659 +perft 3 21249 +perft 4 469701 +perft 5 15434721 +perft 6 365761521 + +id 1 +epd rk1nnrbb/p1p1pppp/1p6/3p1q2/P3P3/2NN4/1PPP1PPP/RKQ2RBB w FAfa - 3 9 +perft 1 29 +perft 2 989 +perft 3 29087 +perft 4 980477 +perft 5 29643404 +perft 6 998848556 + +id 1 +epd bbrk1q1r/ppppppp1/3n4/7p/3Pn3/6PN/PPP1PPNP/BBRK1Q1R w HChc - 2 9 +perft 1 23 +perft 2 712 +perft 3 16551 +perft 4 516177 +perft 5 12995202 +perft 6 411077508 + +id 1 +epd brkbnq1r/p1ppp2p/5ppn/1p6/5P2/1P1P2P1/P1P1P2P/BRKBNQNR w HBhb - 0 9 +perft 1 28 +perft 2 856 +perft 3 24984 +perft 4 780503 +perft 5 23529352 +perft 6 754501112 + +id 1 +epd br1k1bnr/ppppp1pp/4np2/1B2P2q/3P4/8/PPP2PPP/BRKNQ1NR w HB - 3 9 +perft 1 36 +perft 2 1214 +perft 3 40615 +perft 4 1328331 +perft 5 45096834 +perft 6 1470987023 + +id 1 +epd brk1qnrb/pnppp1p1/1p6/5p1p/8/5PPP/PPPPP1R1/BRKNQN1B w Bgb - 0 9 +perft 1 22 +perft 2 551 +perft 3 13111 +perft 4 353317 +perft 5 9040545 +perft 6 259643605 + +id 1 +epd rbbkn1nr/1ppp2pp/p3p3/2q2p2/3P4/6P1/PPPBPP1P/RB1KNQNR w HAha - 0 9 +perft 1 31 +perft 2 1060 +perft 3 31332 +perft 4 1015099 +perft 5 30314172 +perft 6 976268967 + +id 1 +epd rkbbn1nr/ppppp1pp/8/6N1/5p2/1q6/P1PPPPPP/RKBBN1QR w HAha - 0 9 +perft 1 3 +perft 2 72 +perft 3 1919 +perft 4 50827 +perft 5 1400832 +perft 6 39654253 + +id 1 +epd rkb2bnr/pp2pppp/2p1n3/3p4/q2P4/5NP1/PPP1PP1P/RKBNQBR1 w Aha - 0 9 +perft 1 29 +perft 2 861 +perft 3 24504 +perft 4 763454 +perft 5 22763215 +perft 6 731511256 + +id 1 +epd rkbq1nrb/ppppppp1/7p/8/1P1n4/P4P1P/2PPP1P1/RKBNQNRB w GAga - 0 9 +perft 1 25 +perft 2 672 +perft 3 17631 +perft 4 473864 +perft 5 12954224 +perft 6 361237536 + +id 1 +epd rbknb1nr/ppp1qp1p/6p1/3pp3/3P3P/2B1P3/PPP2PP1/RBKN1QNR w HAha - 1 9 +perft 1 27 +perft 2 857 +perft 3 24688 +perft 4 792538 +perft 5 23790033 +perft 6 768247869 + +id 1 +epd rknbbq1r/p1pppppp/1p2N3/8/3n4/2P5/PP1PPPPP/RK1BBQNR w HAha - 4 9 +perft 1 29 +perft 2 763 +perft 3 22138 +perft 4 574054 +perft 5 16926075 +perft 6 447896703 + +id 1 +epd r1nqbbnr/1pppp1pp/1k6/p4p2/8/4P3/PPPP1PPP/RKN1BBNR w HA - 0 9 +perft 1 26 +perft 2 658 +perft 3 17302 +perft 4 464039 +perft 5 12380488 +perft 6 349047256 + +id 1 +epd rkn2qrb/ppp1pppp/6n1/1b1p4/1P6/4PPB1/P1PP2PP/RKNQ1NRB w GAga - 3 9 +perft 1 23 +perft 2 574 +perft 3 14070 +perft 4 370324 +perft 5 9501401 +perft 6 263870337 + +id 1 +epd rbkn2br/ppppp1p1/4np1p/1P5q/8/2P1N3/P2PPPPP/RBK1QNBR w HAha - 1 9 +perft 1 29 +perft 2 992 +perft 3 29506 +perft 4 999564 +perft 5 30148787 +perft 6 1045942540 + +id 1 +epd 1knbqnbr/1ppppp1p/r5p1/p7/7P/2PN2P1/PP1PPP2/RK1BQNBR w HAh - 2 9 +perft 1 26 +perft 2 698 +perft 3 19395 +perft 4 512023 +perft 5 14848229 +perft 6 402599313 + +id 1 +epd rk1qnbbr/pnpppp1p/6p1/1p6/3P4/1P6/P1P1PPPP/RKNQNBBR w HAha - 1 9 +perft 1 20 +perft 2 480 +perft 3 11159 +perft 4 287539 +perft 5 7425917 +perft 6 203194521 + +id 1 +epd rknqnrbb/pp1p2p1/5p1p/2p1p3/2P1P3/P2P4/1P3PPP/RKNQNRBB w FAfa - 0 9 +perft 1 26 +perft 2 679 +perft 3 18116 +perft 4 494953 +perft 5 13790137 +perft 6 392629571 + +id 1 +epd bbrk2qr/pp1p1ppp/3n2n1/2p1p3/3P1P2/6N1/PPP1P1PP/BBRKN1QR w HChc - 0 9 +perft 1 26 +perft 2 790 +perft 3 21521 +perft 4 673269 +perft 5 19259490 +perft 6 617563700 + +id 1 +epd b1krnnqr/1p1ppppp/p1p5/b6B/P7/4P1N1/1PPP1PPP/BRK1N1QR w HB - 2 9 +perft 1 26 +perft 2 625 +perft 3 16451 +perft 4 415452 +perft 5 11490615 +perft 6 304805107 + +id 1 +epd 1rknnbqr/3ppppp/p7/1pp5/4b2P/P4P2/1PPPP1PR/BRKNNBQ1 w Bhb - 1 9 +perft 1 24 +perft 2 757 +perft 3 19746 +perft 4 618777 +perft 5 17275100 +perft 6 544309489 + +id 1 +epd br1nn1rb/pppkpqpp/3p1p2/8/PP6/4N3/1KPPPPPP/BR2NQRB w - - 3 9 +perft 1 24 +perft 2 682 +perft 3 17129 +perft 4 482711 +perft 5 13057308 +perft 6 375033550 + +id 1 +epd rbbkn1qr/pppp2p1/6np/4pp2/7N/7P/PPPPPPPR/RBBK1NQ1 w Aha - 0 9 +perft 1 22 +perft 2 586 +perft 3 14158 +perft 4 409891 +perft 5 10607781 +perft 6 324452612 + +id 1 +epd rk1bn1qr/pppbpppp/4n3/4p3/4P3/5P2/PPPP2PP/RKBB1NQR w HAha - 1 9 +perft 1 22 +perft 2 530 +perft 3 13440 +perft 4 348004 +perft 5 9514787 +perft 6 259898748 + +id 1 +epd rkbnnbqr/1ppp1ppp/p7/4p3/8/QP3P2/P1PPP1PP/RKBNNB1R w HAha - 0 9 +perft 1 29 +perft 2 705 +perft 3 21511 +perft 4 551042 +perft 5 17524731 +perft 6 472356665 + +id 1 +epd 1kbnnqrb/1pp1p1pp/r4p2/p2p4/N4P2/3P4/PPP1P1PP/RKB1NQRB w GAg - 2 9 +perft 1 21 +perft 2 623 +perft 3 14979 +perft 4 437554 +perft 5 11601134 +perft 6 343214006 + +id 1 +epd rbknbn1r/pppp1p1p/4p1q1/8/P1P3Pp/8/1P1PPP2/RBKNBNQR w HAha - 0 9 +perft 1 30 +perft 2 813 +perft 3 24959 +perft 4 708454 +perft 5 23379040 +perft 6 692576573 + +id 1 +epd rk1bb1qr/2pppppp/p2nn3/1p4P1/6QP/8/PPPPPP2/RKNBBN1R w HAha - 2 9 +perft 1 36 +perft 2 857 +perft 3 30124 +perft 4 757524 +perft 5 26485812 +perft 6 696999449 + +id 1 +epd rkn1bbqr/p2ppppp/2p1n3/1p6/4PP2/6PP/PPPP4/RKNNBBQR w HAha - 0 9 +perft 1 33 +perft 2 687 +perft 3 22744 +perft 4 511018 +perft 5 17101732 +perft 6 412778368 + +id 1 +epd rkn1bqrb/pnp1pppp/3p4/8/Pp6/1N2NP2/1PPPP1PP/RK2BQRB w GAga - 0 9 +perft 1 28 +perft 2 591 +perft 3 17174 +perft 4 406025 +perft 5 12182448 +perft 6 312575205 + +id 1 +epd rbk1n1br/ppp1ppqp/2n5/2Np2p1/8/2P5/PPBPPPPP/R1KN1QBR w HAha - 4 9 +perft 1 35 +perft 2 930 +perft 3 30663 +perft 4 844433 +perft 5 27160490 +perft 6 780616047 + +id 1 +epd rknbn1br/1ppp1ppp/p3p3/8/1q6/2P2N1P/P2PPPP1/RKNB1QBR w HAha - 0 9 +perft 1 4 +perft 2 157 +perft 3 3697 +perft 4 138102 +perft 5 3454704 +perft 6 125373395 + +id 1 +epd rkn1qbbr/pp3ppp/4n3/2ppp3/4P1P1/P2P4/1PP2P1P/RKNNQBBR w HAha - 0 9 +perft 1 28 +perft 2 840 +perft 3 24437 +perft 4 771328 +perft 5 23200961 +perft 6 756489357 + +id 1 +epd rkn1qrbb/pp1ppp2/2p1n1p1/7p/2P2P1P/6P1/PP1PP3/RKNNQRBB w FAfa - 1 9 +perft 1 32 +perft 2 867 +perft 3 27595 +perft 4 757836 +perft 5 24485663 +perft 6 688115847 + +id 1 +epd b1rknnrq/bpppp1p1/p6p/5p1P/6P1/4N3/PPPPPP2/BBRKN1RQ w GCgc - 1 9 +perft 1 33 +perft 2 851 +perft 3 28888 +perft 4 763967 +perft 5 26686205 +perft 6 731944177 + +id 1 +epd brkb1nr1/pppppp2/3n2pp/3B4/1P6/4P3/PqPP1PPP/BRK1NNRQ w GBgb - 2 9 +perft 1 4 +perft 2 98 +perft 3 2965 +perft 4 76143 +perft 5 2352530 +perft 6 64251468 + +id 1 +epd brk1nbrq/1ppppn1p/6p1/p4p2/P5P1/5R2/1PPPPP1P/BRKNNB1Q w Bgb - 0 9 +perft 1 29 +perft 2 922 +perft 3 27709 +perft 4 879527 +perft 5 27463717 +perft 6 888881062 + +id 1 +epd brkn1rqb/1p1ppppp/3n4/p1p5/1P3P2/8/PNPPP1PP/BR1KNRQB w fb - 1 9 +perft 1 29 +perft 2 633 +perft 3 19399 +perft 4 469818 +perft 5 15076198 +perft 6 396737074 + +id 1 +epd rb1k1nrq/pbp1pppp/1p1p1n2/8/5P2/4NN1P/PPPPP1P1/RBBK2RQ w GAga - 2 9 +perft 1 28 +perft 2 841 +perft 3 24056 +perft 4 710751 +perft 5 20772996 +perft 6 613798447 + +id 1 +epd rkbbnnrq/p1pp3p/4p1p1/1p3p2/P6P/1P6/1BPPPPP1/RK1BNNRQ w GAga - 0 9 +perft 1 33 +perft 2 957 +perft 3 30668 +perft 4 907217 +perft 5 29735654 +perft 6 903933626 + +id 1 +epd rk2nbrq/p1ppppp1/bpn5/7p/6P1/2N2P2/PPPPP1QP/RKB1NBR1 w GAga - 2 9 +perft 1 24 +perft 2 687 +perft 3 18206 +perft 4 544627 +perft 5 15518417 +perft 6 484217179 + +id 1 +epd rkbn1r1b/pp1pppnp/6q1/2p3p1/5P1P/4N3/PPPPP1P1/RKB1NRQB w FAfa - 1 9 +perft 1 23 +perft 2 831 +perft 3 21254 +perft 4 754622 +perft 5 21126103 +perft 6 744755212 + +id 1 +epd rbknb1rq/ppp1p1p1/3pnp1p/8/6PP/2PP4/PP2PP2/RBKNBNRQ w GAga - 0 9 +perft 1 31 +perft 2 838 +perft 3 26800 +perft 4 736910 +perft 5 24008129 +perft 6 677776408 + +id 1 +epd rknbb1rq/p1pn1ppp/4p3/1p1p4/2P5/1P2N1P1/P2PPP1P/RKNBB1RQ w GAga - 1 9 +perft 1 29 +perft 2 830 +perft 3 24798 +perft 4 721630 +perft 5 22243832 +perft 6 660040360 + +id 1 +epd rk1nbbrq/pp1p1ppp/3n4/P3p3/2p4P/8/1PPPPPP1/RKNNBBRQ w GAga - 1 9 +perft 1 24 +perft 2 484 +perft 3 12776 +perft 4 297419 +perft 5 8379748 +perft 6 214004367 + +id 1 +epd rknnbr1b/ppp2pqp/3p4/4p1p1/7P/3P1P2/PPP1P1P1/RKNNBRQB w FAfa - 0 9 +perft 1 32 +perft 2 838 +perft 3 26408 +perft 4 740701 +perft 5 23472124 +perft 6 699211365 + +id 1 +epd rb1k1rbq/ppppN1pp/2nn4/5p2/7P/8/PPPPPPP1/RBK1NRBQ w FA - 1 9 +perft 1 27 +perft 2 800 +perft 3 22785 +perft 4 701742 +perft 5 20804424 +perft 6 660917073 + +id 1 +epd r1nbnrbq/kppppp1p/6p1/8/p1PP1P2/4P3/PP4PP/RKNBNRBQ w FA - 1 9 +perft 1 28 +perft 2 757 +perft 3 21198 +perft 4 602699 +perft 5 17180857 +perft 6 507618340 + +id 1 +epd rkn1rbbq/p1pppppp/2n5/1pP5/8/1N2P3/PP1P1PPP/RK1NRBBQ w EAea - 1 9 +perft 1 22 +perft 2 483 +perft 3 11890 +perft 4 283679 +perft 5 7497674 +perft 6 191130942 + +id 1 +epd rknnrqbb/2pppppp/8/p7/Np3P2/3P4/PPP1P1PP/RKN1RQBB w EAea - 0 9 +perft 1 25 +perft 2 536 +perft 3 14456 +perft 4 339180 +perft 5 9694947 +perft 6 245669668 + +id 1 +epd bb1rknrn/1qppppp1/1p4B1/p6N/8/2P5/PP1PPPPP/B1QRK1RN w GDgd - 1 9 +perft 1 32 +perft 2 715 +perft 3 22421 +perft 4 575008 +perft 5 17860156 +perft 6 502410909 + +id 1 +epd b1rbknrn/qpp1ppp1/p6p/3p4/2P5/1P1P1P2/P3P1PP/BQRBKNRN w GCgc - 0 9 +perft 1 30 +perft 2 818 +perft 3 24421 +perft 4 688711 +perft 5 20981488 +perft 6 611986786 + +id 1 +epd bqkrnbrn/1pp1pp1p/p7/1B1p2p1/4P3/7P/PPPP1PP1/BQKRN1RN w - - 0 9 +perft 1 28 +perft 2 676 +perft 3 18366 +perft 4 478054 +perft 5 13126287 +perft 6 363765666 + +id 1 +epd bqrknrnb/1p2ppp1/p1pp3p/8/3P1P2/1PP5/P3P1PP/BQRKNRNB w FCfc - 0 9 +perft 1 31 +perft 2 646 +perft 3 20686 +perft 4 455607 +perft 5 14984618 +perft 6 349082278 + +id 1 +epd qbbrkn1r/pppppp1p/8/6p1/2P1Pn1P/6N1/PP1P1PP1/QBBRKNR1 w GDd - 3 9 +perft 1 20 +perft 2 532 +perft 3 11581 +perft 4 303586 +perft 5 7512432 +perft 6 202967948 + +id 1 +epd 1rbbknr1/p1ppp1pp/1pq2pn1/8/3P4/P3P3/QPP2PPP/1RBBKNRN w GBgb - 3 9 +perft 1 31 +perft 2 1002 +perft 3 30581 +perft 4 999607 +perft 5 30642468 +perft 6 1009228283 + +id 1 +epd qrbkn1rn/pppp1ppp/8/6b1/P1P1Pp2/8/1P1P2PP/QRBKNBRN w GBgb - 0 9 +perft 1 22 +perft 2 505 +perft 3 12447 +perft 4 304863 +perft 5 8192621 +perft 6 214730959 + +id 1 +epd qrbk1rnb/p2ppp1p/5n2/1pp3p1/8/7P/PPPPPPPN/QRBKR1NB w Bfb - 0 9 +perft 1 20 +perft 2 619 +perft 3 13448 +perft 4 449630 +perft 5 10571176 +perft 6 369603424 + +id 1 +epd qbrkb1r1/ppp2ppp/3pn1n1/P3p3/4P3/3P4/1PP2PPP/QBRKBNRN w GCgc - 1 9 +perft 1 26 +perft 2 755 +perft 3 20596 +perft 4 604483 +perft 5 17164382 +perft 6 510878835 + +id 1 +epd qrkbb1r1/ppp1pnpp/3p2n1/5p2/1P3P2/2Q3N1/P1PPP1PP/1RKBB1RN w GBgb - 0 9 +perft 1 35 +perft 2 918 +perft 3 32244 +perft 4 870888 +perft 5 30933394 +perft 6 867833733 + +id 1 +epd qrknbbrn/ppp1ppp1/8/7p/2Bp4/4PPP1/PPPP3P/QRKNB1RN w GBgb - 0 9 +perft 1 27 +perft 2 593 +perft 3 16168 +perft 4 376808 +perft 5 10422676 +perft 6 258348640 + +id 1 +epd qrk1brnb/ppppp3/4n2p/5pp1/2PP4/2N4P/PP2PPP1/QRK1BRNB w FBfb - 2 9 +perft 1 24 +perft 2 672 +perft 3 17447 +perft 4 506189 +perft 5 13765777 +perft 6 414930519 + +id 1 +epd qbrknrb1/p2ppppp/2p3n1/8/p4P2/6PP/1PPPP3/QBRKNRBN w FCfc - 0 9 +perft 1 29 +perft 2 759 +perft 3 23235 +perft 4 634493 +perft 5 20416668 +perft 6 584870558 + +id 1 +epd 1rkb1rbn/p1pp1ppp/3np3/1p6/4qP2/3NB3/PPPPPRPP/QRKB3N w Bfb - 0 9 +perft 1 22 +perft 2 923 +perft 3 22585 +perft 4 914106 +perft 5 24049880 +perft 6 957218571 + +id 1 +epd 1rknrbbn/p1pp1p1p/8/1p2p1p1/4qPP1/2P5/PP1PP1BP/QRKNR1BN w EBeb - 0 9 +perft 1 28 +perft 2 1309 +perft 3 36355 +perft 4 1568968 +perft 5 44576409 +perft 6 1846382333 + +id 1 +epd qrk1rn1b/ppppp2p/4n3/3b1pp1/4P2P/5BP1/PPPP1P2/QRKNRNB1 w EBeb - 3 9 +perft 1 26 +perft 2 839 +perft 3 22189 +perft 4 726354 +perft 5 19978260 +perft 6 661207281 + +id 1 +epd bbrqk1rn/pp1ppppp/8/2p5/2P1P3/5n1P/PPBP1PP1/B1RQKNRN w GCgc - 1 9 +perft 1 3 +perft 2 95 +perft 3 2690 +perft 4 85038 +perft 5 2518864 +perft 6 80775549 + +id 1 +epd brqbk2n/pppppprp/8/6p1/1P3n2/5P2/P1PPP1PP/R1QBKNRN w Gb - 2 9 +perft 1 22 +perft 2 593 +perft 3 13255 +perft 4 362760 +perft 5 8922397 +perft 6 253271592 + +id 1 +epd brqknbr1/pp3ppp/3p2n1/2p1p3/2P5/5P2/PPKPP1PP/BRQ1NBRN w gb - 0 9 +perft 1 21 +perft 2 590 +perft 3 13190 +perft 4 397355 +perft 5 9581695 +perft 6 304103516 + +id 1 +epd 1rqknrnb/2pp1ppp/p3p3/1p6/P2P4/5bP1/1PP1PP1P/BRQKNRNB w FBfb - 0 9 +perft 1 24 +perft 2 737 +perft 3 20052 +perft 4 598439 +perft 5 17948681 +perft 6 536330341 + +id 1 +epd rbb1k1rn/p1pqpppp/6n1/1p1p4/5P2/3PP3/PPP1K1PP/RBBQ1NRN w ga - 3 9 +perft 1 24 +perft 2 694 +perft 3 16773 +perft 4 513782 +perft 5 13094823 +perft 6 419402704 + +id 1 +epd rqbbknr1/1ppp2pp/p5n1/4pp2/P7/1PP5/1Q1PPPPP/R1BBKNRN w GAga - 0 9 +perft 1 24 +perft 2 600 +perft 3 15347 +perft 4 408207 +perft 5 11029596 +perft 6 308553169 + +id 1 +epd rqbknbrn/2pppppp/6Q1/pp6/8/2P5/PP1PPPPP/R1BKNBRN w GAga - 2 9 +perft 1 40 +perft 2 949 +perft 3 34100 +perft 4 889887 +perft 5 31296485 +perft 6 881529007 + +id 1 +epd rqbknr1b/pp1ppp2/2p2n1p/6p1/8/3P1PPP/PPP1P3/RQBKNRNB w FAfa - 0 9 +perft 1 20 +perft 2 560 +perft 3 12275 +perft 4 373921 +perft 5 8687544 +perft 6 277906201 + +id 1 +epd rbqkbnrn/p3pppp/1p6/3p4/P1p3P1/1P6/1QPPPP1P/RB1KBNRN w GAga - 0 9 +perft 1 30 +perft 2 1155 +perft 3 35865 +perft 4 1351455 +perft 5 43092716 +perft 6 1614019629 + +id 1 +epd rqkbb1rn/p1p1pppn/1p1p4/7p/4PP2/7P/PPPPB1P1/RQK1BNRN w GAga - 1 9 +perft 1 30 +perft 2 701 +perft 3 20804 +perft 4 515942 +perft 5 15450970 +perft 6 401499189 + +id 1 +epd rqknbbrn/1p2pp1p/3p2p1/p1p5/P2P4/1P6/1KP1PPPP/RQ1NBBRN w ga - 0 9 +perft 1 28 +perft 2 756 +perft 3 21655 +perft 4 610320 +perft 5 17989811 +perft 6 525585996 + +id 1 +epd rqknbrnb/1pp3pp/5p2/p2pp3/P7/3PPN2/1PP2PPP/RQKNBR1B w FAfa - 0 9 +perft 1 26 +perft 2 731 +perft 3 19509 +perft 4 550395 +perft 5 15209404 +perft 6 439767476 + +id 1 +epd rbqkr1bn/p1pppp1p/1p1n4/6p1/7P/3P1PP1/PPP1P3/RBQKNRBN w FAa - 0 9 +perft 1 27 +perft 2 586 +perft 3 16282 +perft 4 381604 +perft 5 10905865 +perft 6 274364342 + +id 1 +epd rqk1nrb1/ppbp1ppp/4p1n1/2p5/7P/1PP5/P2PPPP1/RQKBNRBN w FAfa - 1 9 +perft 1 27 +perft 2 749 +perft 3 21480 +perft 4 602318 +perft 5 18084787 +perft 6 520547029 + +id 1 +epd rqknrbbn/pp1p1ppp/4p3/2p5/3P2P1/7P/PPP1PP2/RQKNRBBN w EAa - 0 9 +perft 1 20 +perft 2 533 +perft 3 11829 +perft 4 336248 +perft 5 8230417 +perft 6 245871540 + +id 1 +epd rqknrnbb/pp1ppp1p/2p3p1/8/8/1P2P1NP/P1PP1PP1/RQKNR1BB w EAea - 0 9 +perft 1 22 +perft 2 633 +perft 3 14480 +perft 4 441877 +perft 5 10827868 +perft 6 343525739 + +id 1 +epd 1brkq1rn/2pppppp/1p2n3/p2bN3/8/7P/PPPPPPP1/BBRKQ1RN w GCgc - 2 9 +perft 1 27 +perft 2 748 +perft 3 20134 +perft 4 580054 +perft 5 16010135 +perft 6 475206624 + +id 1 +epd brkbqnrn/2pp1ppp/8/1p2p3/Pp2N3/8/2PPPPPP/BRKBQNR1 w GBgb - 0 9 +perft 1 30 +perft 2 827 +perft 3 25308 +perft 4 757837 +perft 5 23746165 +perft 6 751690068 + +id 1 +epd brk1nbrn/pp1ppppp/2p5/7P/5P2/q2P4/PPP1P1P1/BRKQNBRN w GBgb - 1 9 +perft 1 15 +perft 2 471 +perft 3 8716 +perft 4 276424 +perft 5 5960901 +perft 6 190316951 + +id 1 +epd brkqnrnb/1p1pp1p1/p4p2/2p4p/8/P2PP3/1PP1QPPP/BRK1NRNB w FBfb - 0 9 +perft 1 24 +perft 2 479 +perft 3 12584 +perft 4 280081 +perft 5 7830230 +perft 6 190419716 + +id 1 +epd rbbkqnrn/2ppp2p/pp3p2/6p1/P6P/8/RPPPPPP1/1BBKQNRN w Gga - 0 9 +perft 1 21 +perft 2 523 +perft 3 12125 +perft 4 328733 +perft 5 8322614 +perft 6 242240658 + +id 1 +epd rkbbqr1n/1ppppppn/7p/p7/4P3/2P2P2/PP1PB1PP/RKB1QNRN w GAa - 3 9 +perft 1 27 +perft 2 563 +perft 3 16026 +perft 4 372148 +perft 5 11105151 +perft 6 283211800 + +id 1 +epd rkbqnbrn/ppppp3/8/5ppp/2P3P1/7P/PPQPPP2/RKB1NBRN w GAga - 0 9 +perft 1 28 +perft 2 639 +perft 3 19250 +perft 4 469250 +perft 5 14872172 +perft 6 384663405 + +id 1 +epd rkb1nrnb/pppp1pp1/5q1p/8/P3p3/4R1P1/1PPPPP1P/1KBQNRNB w Ffa - 0 9 +perft 1 28 +perft 2 873 +perft 3 23690 +perft 4 720814 +perft 5 20209424 +perft 6 625281937 + +id 1 +epd rbkqb1rn/1p1ppppp/4n3/p1p5/8/3PBP2/PPP1P1PP/RBKQ1NRN w GAga - 0 9 +perft 1 26 +perft 2 798 +perft 3 21416 +perft 4 667496 +perft 5 18475618 +perft 6 591681956 + +id 1 +epd rk1qbnrn/1p1ppppp/1b6/p1p5/P7/2P3NP/1P1PPPP1/RKQBB1RN w GAga - 0 9 +perft 1 22 +perft 2 506 +perft 3 12313 +perft 4 301029 +perft 5 7891676 +perft 6 205739580 + +id 1 +epd rk1nbbrn/ppp1ppp1/8/3p3p/1P1P2q1/5PB1/P1P1P1PP/RKQN1BRN w GAga - 1 9 +perft 1 31 +perft 2 956 +perft 3 29219 +perft 4 903799 +perft 5 27827461 +perft 6 876341492 + +id 1 +epd rkqnbr1b/pp1pppp1/7p/2p2n2/P2P4/7N/RPP1PPPP/1KQNBR1B w Ffa - 0 9 +perft 1 31 +perft 2 750 +perft 3 24267 +perft 4 646252 +perft 5 21639104 +perft 6 617064197 + +id 1 +epd rbkq1rbn/2p1pppp/pp3n2/3p4/5P2/3N2N1/PPPPP1PP/RBKQR1B1 w Afa - 2 9 +perft 1 26 +perft 2 647 +perft 3 18027 +perft 4 465119 +perft 5 13643783 +perft 6 369702807 + +id 1 +epd rkqbr1bn/p2ppppp/1pp2n2/8/5P2/3P1N2/PPP1PRPP/RKQB2BN w Aa - 3 9 +perft 1 24 +perft 2 574 +perft 3 14593 +perft 4 371597 +perft 5 10066892 +perft 6 271121237 + +id 1 +epd rk1qrbbn/p1ppp1pp/1p2n3/5p2/1P6/K3N3/P1PPPPPP/R1Q1RBBN w ea - 0 9 +perft 1 25 +perft 2 548 +perft 3 14069 +perft 4 340734 +perft 5 9043111 +perft 6 235545764 + +id 1 +epd rkqnrnbb/pp1pp3/2p5/5ppp/8/PP4NP/2PPPPP1/RKQNR1BB w EAea - 0 9 +perft 1 23 +perft 2 727 +perft 3 18228 +perft 4 566572 +perft 5 15078056 +perft 6 471296844 + +id 1 +epd bbrknq1r/ppppppp1/8/7p/5n2/3P4/PPP1PNPP/BBKRNQR1 w c - 0 9 +perft 1 21 +perft 2 610 +perft 3 13300 +perft 4 394705 +perft 5 9605845 +perft 6 293532398 + +id 1 +epd brkbnqr1/2pppnpp/pp3p2/8/4PPPP/8/PPPP4/BRKBNQRN w GBgb - 1 9 +perft 1 30 +perft 2 757 +perft 3 23908 +perft 4 621332 +perft 5 20360394 +perft 6 548380577 + +id 1 +epd brk1qb1n/ppppppr1/2n3pp/8/2P3P1/2N5/PP1PPP1P/BR1KQBRN w b - 1 9 +perft 1 26 +perft 2 570 +perft 3 15537 +perft 4 352883 +perft 5 10081351 +perft 6 242864559 + +id 1 +epd brknq1nb/pp2prpp/8/2pP1p2/6P1/2N5/PPPP1P1P/BRK1QRNB w FBb - 1 9 +perft 1 33 +perft 2 830 +perft 3 27897 +perft 4 764915 +perft 5 26262884 +perft 6 765831403 + +id 1 +epd rbbk1qrn/ppp1p1pp/5p2/3p1n2/7N/P7/1PPPPPPP/RBB1KQRN w ga - 0 9 +perft 1 21 +perft 2 562 +perft 3 13060 +perft 4 378883 +perft 5 9520963 +perft 6 290579255 + +id 1 +epd rk1b1qrn/ppp1pppp/5n2/3pN3/P6P/7b/1PPPPPP1/RKBB1QRN w GAga - 4 9 +perft 1 28 +perft 2 677 +perft 3 19235 +perft 4 488740 +perft 5 14354779 +perft 6 383207197 + +id 1 +epd rkbnqbrn/pp1ppp1p/2p5/6p1/P7/4P3/KPPPQPPP/R1BN1BRN w - - 3 9 +perft 1 28 +perft 2 585 +perft 3 17443 +perft 4 401483 +perft 5 12574541 +perft 6 310495538 + +id 1 +epd rk1nqrnb/pbpppp2/1p4p1/7p/P7/5NP1/1PPPPPBP/RKBNQR2 w FAfa - 2 9 +perft 1 26 +perft 2 774 +perft 3 21626 +perft 4 645200 +perft 5 19093408 +perft 6 576325868 + +id 1 +epd rbknb1rn/p1pp2pp/1p6/4pp2/1q3P1B/2N5/PPPPPNPP/RBK2QR1 w GAga - 2 9 +perft 1 31 +perft 2 1206 +perft 3 36940 +perft 4 1374158 +perft 5 42849564 +perft 6 1555711209 + +id 1 +epd rk1bbqrn/pp1pp1pp/3n4/5p2/3p4/1PP5/PK2PPPP/R1NBBQRN w ga - 0 9 +perft 1 21 +perft 2 629 +perft 3 14059 +perft 4 429667 +perft 5 10587910 +perft 6 332632033 + +id 1 +epd rknqbbr1/p1pp1pp1/1p4n1/4p2p/4P1P1/6RB/PPPP1P1P/RKNQB2N w Aga - 0 9 +perft 1 27 +perft 2 753 +perft 3 20918 +perft 4 593155 +perft 5 17318772 +perft 6 507563675 + +id 1 +epd rknqbr1b/pppp1ppp/4p2n/8/1P3P2/4P3/P1PPN1PP/RKNQBR1B w FAfa - 2 9 +perft 1 26 +perft 2 623 +perft 3 17177 +perft 4 460663 +perft 5 13389799 +perft 6 383508368 + +id 1 +epd r2kqrbn/bppppppp/2n5/p4B2/5P2/2P5/PP1PP1PP/1RKNQRBN w F - 2 9 +perft 1 39 +perft 2 1026 +perft 3 37800 +perft 4 1011922 +perft 5 35946987 +perft 6 992756232 + +id 1 +epd rk1bqrb1/ppppppp1/1n6/7p/2P2P1n/4P1Q1/PP1P2PP/RKNB1RBN w FAfa - 0 9 +perft 1 35 +perft 2 760 +perft 3 25817 +perft 4 610557 +perft 5 21014787 +perft 6 536852043 + +id 1 +epd rkq1rb1n/ppppp1pp/1n6/5p2/PPb2P2/8/1KPPP1PP/R1NQRBBN w ea - 1 9 +perft 1 27 +perft 2 754 +perft 3 21009 +perft 4 568788 +perft 5 16461795 +perft 6 448313956 + +id 1 +epd rknqr2b/pppnp1pp/3p4/3b1p2/8/1N1P2N1/PPP1PPPP/RKQ1R1BB w EAea - 1 9 +perft 1 27 +perft 2 803 +perft 3 23708 +perft 4 700453 +perft 5 21875031 +perft 6 654754840 + +id 1 +epd bbrknrqn/ppppp1pB/8/2P2p1p/8/5N2/PP1PPPPP/B1RK1RQN w FCfc - 0 9 +perft 1 30 +perft 2 799 +perft 3 23923 +perft 4 671112 +perft 5 20532790 +perft 6 603059376 + +id 1 +epd brkbnrq1/1pppp1p1/6np/p4p2/4P3/1PP5/P1KP1PPP/BR1BNRQN w fb - 1 9 +perft 1 27 +perft 2 726 +perft 3 19329 +perft 4 555622 +perft 5 15156662 +perft 6 457601127 + +id 1 +epd brknrbq1/1p1p1ppp/p3p1n1/2p5/8/1P1BPP2/P1PP2PP/BRKNR1QN w EBeb - 0 9 +perft 1 36 +perft 2 786 +perft 3 27868 +perft 4 655019 +perft 5 22852433 +perft 6 577223409 + +id 1 +epd brknrqnb/p2ppp1p/2p5/1p6/3P2p1/P1P1N3/1P2PPPP/BRK1RQNB w EBeb - 0 9 +perft 1 23 +perft 2 649 +perft 3 15169 +perft 4 440504 +perft 5 10687843 +perft 6 320881984 + +id 1 +epd rbbk1rqn/1ppppppp/3n4/p7/2P5/3N4/PP1PPPPP/RBB1KRQN w fa - 1 9 +perft 1 20 +perft 2 478 +perft 3 11094 +perft 4 275250 +perft 5 7094988 +perft 6 185488058 + +id 1 +epd rkbbnrqn/p2p1ppp/1p2p3/8/P1p1P3/1BP5/1P1P1PPP/RKB1NRQN w FAfa - 0 9 +perft 1 22 +perft 2 570 +perft 3 13295 +perft 4 346811 +perft 5 8671852 +perft 6 229898448 + +id 1 +epd rkb1rb1n/ppppppqp/8/2n3p1/2P1P1P1/8/PP1P1P1P/RKBNRBQN w EAea - 1 9 +perft 1 23 +perft 2 663 +perft 3 16212 +perft 4 490748 +perft 5 12900485 +perft 6 404944553 + +id 1 +epd rkb1rqnb/pppp3p/2n3p1/4pp2/P2P3P/2P5/1P2PPP1/RKBNRQNB w EAea - 0 9 +perft 1 25 +perft 2 845 +perft 3 22188 +perft 4 741972 +perft 5 20276176 +perft 6 683290790 + +id 1 +epd rbk1brqn/ppp1pppp/8/3p4/7P/1P4P1/2PPPP2/RBKNBRQN w FAfa - 0 9 +perft 1 24 +perft 2 526 +perft 3 13862 +perft 4 322175 +perft 5 9054028 +perft 6 222704171 + +id 1 +epd rknbbrqn/pp3pp1/4p3/2pp3p/2P5/8/PPBPPPPP/RKN1BRQN w FAfa - 0 9 +perft 1 26 +perft 2 756 +perft 3 19280 +perft 4 559186 +perft 5 14697705 +perft 6 433719427 + +id 1 +epd 1knrbbqn/rp1p1ppp/p3p3/2p5/8/5P1P/PPPPP1P1/RKNRBBQN w DAd - 0 9 +perft 1 26 +perft 2 539 +perft 3 15194 +perft 4 345070 +perft 5 10223443 +perft 6 248715580 + +id 1 +epd rknr1qnb/ppp1p1pp/3p2b1/8/4p3/1P3P1P/P1PP2P1/RKNRBQNB w DAda - 0 9 +perft 1 25 +perft 2 701 +perft 3 18969 +perft 4 561369 +perft 5 16047041 +perft 6 496340789 + +id 1 +epd rbk1r1bn/ppppp1pp/4n3/5p2/1P3P2/4N2P/PqPPP1P1/RBK1RQBN w EAea - 1 9 +perft 1 2 +perft 2 60 +perft 3 1319 +perft 4 41765 +perft 5 1017864 +perft 6 33183408 + +id 1 +epd r1nbrqbn/k1ppp1pp/1p6/p4p2/2P5/6PQ/PP1PPP1P/RKNBR1BN w EA - 0 9 +perft 1 27 +perft 2 699 +perft 3 20436 +perft 4 561765 +perft 5 17192121 +perft 6 499247248 + +id 1 +epd rknrqbbn/1pp1pp2/p5p1/3p3p/6P1/PN5P/1PPPPP2/RK1RQBBN w DAda - 0 9 +perft 1 23 +perft 2 611 +perft 3 15515 +perft 4 435927 +perft 5 11917036 +perft 6 352885930 + +id 1 +epd rknrqn1b/p1pp1ppb/8/1p2p1Qp/3P4/3N4/PPP1PPPP/RK1R1NBB w DAda - 0 9 +perft 1 45 +perft 2 1170 +perft 3 48283 +perft 4 1320341 +perft 5 52213677 +perft 6 1500007485 + +id 1 +epd bbkrnrnq/p2p1ppp/2p1p3/1p6/1P2Q3/6P1/P1PPPP1P/BBKRNRN1 w - - 0 9 +perft 1 41 +perft 2 1035 +perft 3 39895 +perft 4 1035610 +perft 5 38555608 +perft 6 1037686769 + +id 1 +epd brkbnr2/1ppppp1p/7n/p5N1/P2q4/8/1PPPPPPP/BRKBNRQ1 w FBfb - 1 9 +perft 1 22 +perft 2 869 +perft 3 19234 +perft 4 679754 +perft 5 16453359 +perft 6 567287944 + +id 1 +epd brknrbnq/p1ppppp1/1p6/7p/2PP4/5P2/PPK1P1PP/BR1NRBNQ w eb - 1 9 +perft 1 23 +perft 2 641 +perft 3 14748 +perft 4 422240 +perft 5 10192718 +perft 6 302864305 + +id 1 +epd brk1r1qb/pp1ppnpp/2p2pn1/8/6N1/2N3P1/PPPPPP1P/BRK1R1QB w EBeb - 3 9 +perft 1 32 +perft 2 863 +perft 3 28379 +perft 4 773191 +perft 5 25848794 +perft 6 720443112 + +id 1 +epd rbbk1rnq/pppp1pp1/4p2p/8/3P2n1/4BN1P/PPP1PPP1/RB1K1RNQ w FAfa - 3 9 +perft 1 26 +perft 2 628 +perft 3 16151 +perft 4 411995 +perft 5 11237919 +perft 6 300314373 + +id 1 +epd rkbbnr1q/p1pppppp/5n2/1p5B/PP6/4P3/2PP1PPP/RKB1NRNQ w FAfa - 0 9 +perft 1 30 +perft 2 692 +perft 3 21036 +perft 4 519283 +perft 5 16025428 +perft 6 420887328 + +id 1 +epd rkb1rbnq/1pppp1pp/5p2/p7/5n1P/1PN3P1/P1PPPP2/RKB1RBNQ w EAea - 0 9 +perft 1 32 +perft 2 825 +perft 3 27130 +perft 4 697251 +perft 5 23593363 +perft 6 622249676 + +id 1 +epd rkbnrnqb/1ppp1p1p/p5p1/4p3/4P3/2N2P2/PPPP2PP/RKBR1NQB w Aea - 0 9 +perft 1 24 +perft 2 487 +perft 3 13300 +perft 4 301989 +perft 5 8782713 +perft 6 215787079 + +id 1 +epd rbknbr1q/pppp2pp/4p3/5p1n/1P2P2N/8/P1PP1PPP/RBKNBR1Q w FAfa - 0 9 +perft 1 23 +perft 2 571 +perft 3 13799 +perft 4 365272 +perft 5 9224232 +perft 6 257288920 + +id 1 +epd rknbb1nq/pppppr2/5pp1/7p/8/1N4P1/PPPPPP1P/RK1BBRNQ w FAa - 2 9 +perft 1 26 +perft 2 548 +perft 3 15618 +perft 4 350173 +perft 5 10587626 +perft 6 253006082 + +id 1 +epd rknr1bnq/p2pp1pp/1p3p2/2p4b/6PP/2P2N2/PP1PPP2/RKNRBB1Q w DAda - 1 9 +perft 1 25 +perft 2 502 +perft 3 13150 +perft 4 279098 +perft 5 7824941 +perft 6 175766730 + +id 1 +epd rknrb1qb/ppp1pppp/3p4/8/4P1nP/2P5/PPKP1PP1/R1NRBNQB w da - 1 9 +perft 1 23 +perft 2 643 +perft 3 14849 +perft 4 426616 +perft 5 10507328 +perft 6 312096061 + +id 1 +epd rbk1rnbq/pppp1npp/4p3/5p2/4P1P1/7P/PPPP1P1N/RBKNR1BQ w EAea - 1 9 +perft 1 24 +perft 2 591 +perft 3 15178 +perft 4 376988 +perft 5 10251465 +perft 6 263574861 + +id 1 +epd rknbrnb1/p1pppp1p/1p6/3N2p1/P3q1P1/8/1PPPPP1P/RKNBR1BQ w EAea - 1 9 +perft 1 28 +perft 2 948 +perft 3 27343 +perft 4 864588 +perft 5 26241141 +perft 6 812343987 + +id 1 +epd rknrn1b1/ppppppqp/8/6p1/2P5/2P1BP2/PP2P1PP/RKNRNB1Q w DAda - 1 9 +perft 1 31 +perft 2 807 +perft 3 24360 +perft 4 672973 +perft 5 20455205 +perft 6 588518645 + +id 1 +epd 1k1rnqbb/npppppp1/r7/p2B3p/5P2/1N4P1/PPPPP2P/RK1RNQB1 w DAd - 0 9 +perft 1 40 +perft 2 1122 +perft 3 44297 +perft 4 1249989 +perft 5 48711073 +perft 6 1412437357 + +id 1 +epd bbqr1rkn/pp1ppppp/8/2p5/1P2P1n1/7N/P1PP1P1P/BBQRKR1N w FD - 0 9 +perft 1 26 +perft 2 841 +perft 3 22986 +perft 4 746711 +perft 5 21328001 +perft 6 705170410 + +id 1 +epd bqkr1rnn/1ppp1ppp/p4b2/4p3/P7/3PP2N/1PP2PPP/BQRBKR1N w FC - 3 9 +perft 1 24 +perft 2 500 +perft 3 12802 +perft 4 293824 +perft 5 7928916 +perft 6 197806842 + +id 1 +epd bqrkrbnn/1pp1ppp1/8/p6p/3p4/P3P2P/QPPP1PP1/B1RKRBNN w ECec - 0 9 +perft 1 31 +perft 2 592 +perft 3 18585 +perft 4 396423 +perft 5 12607528 +perft 6 298629240 + +id 1 +epd bqkrrnnb/2p1pppp/p7/1P1p4/8/2R3P1/PP1PPP1P/BQ1KRNNB w E - 0 9 +perft 1 42 +perft 2 1124 +perft 3 45187 +perft 4 1276664 +perft 5 50052573 +perft 6 1483524894 + +id 1 +epd qbbrkrn1/p1pppn1p/8/1p3Pp1/2P5/8/PP1PPP1P/QBBRKRNN w FDfd - 0 9 +perft 1 21 +perft 2 577 +perft 3 13244 +perft 4 392131 +perft 5 9683808 +perft 6 300294295 + +id 1 +epd qrbbkrnn/pp1p2pp/4p3/5p2/2p2P1P/2P5/PP1PP1P1/QRBBKRNN w FBfb - 0 9 +perft 1 21 +perft 2 571 +perft 3 12736 +perft 4 345681 +perft 5 8239872 +perft 6 228837930 + +id 1 +epd qrbkrbn1/1pp1pppp/p2p4/8/5PPn/2P5/PP1PP3/QRBKRBNN w EBeb - 0 9 +perft 1 18 +perft 2 466 +perft 3 9443 +perft 4 257776 +perft 5 5679073 +perft 6 162883949 + +id 1 +epd qrb1rnnb/pp1p1ppp/2pk4/4p3/1P2P3/1R6/P1PP1PPP/Q1BKRNNB w E - 4 9 +perft 1 37 +perft 2 760 +perft 3 26863 +perft 4 562201 +perft 5 19486022 +perft 6 421740856 + +id 1 +epd qbrkbrn1/p1pppp1p/6n1/1p4p1/1P6/5P2/P1PPPBPP/QBRK1RNN w FCfc - 1 9 +perft 1 33 +perft 2 824 +perft 3 27385 +perft 4 750924 +perft 5 25176664 +perft 6 734656217 + +id 1 +epd qrkbbr2/2pppppp/5nn1/pp1Q4/P7/3P4/1PP1PPPP/1RKBBRNN w FBfb - 0 9 +perft 1 42 +perft 2 1147 +perft 3 44012 +perft 4 1311247 +perft 5 48216013 +perft 6 1522548864 + +id 1 +epd qrkrbbnn/pp2pp2/2pp2pp/1B6/P7/4P3/1PPP1PPP/QRKRB1NN w DBdb - 0 9 +perft 1 26 +perft 2 464 +perft 3 12653 +perft 4 242892 +perft 5 6928220 +perft 6 142507795 + +id 1 +epd qrkrbnnb/p1pp1pp1/1p5p/4p3/1P6/6PN/PKPPPP1P/QR1RBN1B w db - 0 9 +perft 1 29 +perft 2 705 +perft 3 20000 +perft 4 529810 +perft 5 15055365 +perft 6 419552571 + +id 1 +epd qbrkr1bn/p1p1pp1p/1p1p2n1/6p1/3P1P2/4P3/PPP3PP/QBKRRNBN w ec - 2 9 +perft 1 23 +perft 2 613 +perft 3 14835 +perft 4 426484 +perft 5 10747407 +perft 6 323905533 + +id 1 +epd qrk1rnb1/p1pp1ppp/1p2Bbn1/8/4P3/6P1/PPPP1P1P/QRK1RNBN w EBeb - 1 9 +perft 1 28 +perft 2 927 +perft 3 24887 +perft 4 846839 +perft 5 23063284 +perft 6 807913585 + +id 1 +epd 1qkrnbbn/1rpppppp/pp6/5N2/P4P2/8/1PPPP1PP/QRKRNBB1 w DBd - 3 9 +perft 1 30 +perft 2 542 +perft 3 16646 +perft 4 345172 +perft 5 10976745 +perft 6 251694423 + +id 1 +epd qrkr2bb/pppppppp/8/1n2n3/1N5P/1P6/P1PPPPP1/QRKR1NBB w DBdb - 1 9 +perft 1 28 +perft 2 719 +perft 3 21048 +perft 4 562015 +perft 5 17351761 +perft 6 479400272 + +id 1 +epd bbrqkrnn/3ppppp/8/ppp5/6P1/4P2N/PPPPKP1P/BBRQ1R1N w fc - 0 9 +perft 1 21 +perft 2 704 +perft 3 16119 +perft 4 546215 +perft 5 13676371 +perft 6 470796854 + +id 1 +epd brqbkrnn/1pp2p1p/3pp1p1/p5N1/8/1P6/P1PPPPPP/BRQBK1RN w Bfb - 0 9 +perft 1 34 +perft 2 688 +perft 3 22827 +perft 4 505618 +perft 5 16639723 +perft 6 402140795 + +id 1 +epd br1krb1n/2qppppp/pp3n2/8/1P4P1/8/P1PPPP1P/1RQKRBNN w EBeb - 0 9 +perft 1 24 +perft 2 945 +perft 3 23943 +perft 4 926427 +perft 5 25019636 +perft 6 959651619 + +id 1 +epd brqkr1nb/2ppp1pp/1p2np2/p7/2P1PN2/8/PP1P1PPP/BRQKRN1B w EBeb - 0 9 +perft 1 28 +perft 2 675 +perft 3 19728 +perft 4 504128 +perft 5 15516491 +perft 6 417396563 + +id 1 +epd rbbqkrnn/3pppp1/p7/1pp4p/2P1P2P/8/PP1P1PP1/RBBQKRNN w FAfa - 0 9 +perft 1 26 +perft 2 671 +perft 3 18164 +perft 4 496806 +perft 5 14072641 +perft 6 404960259 + +id 1 +epd rqbbkr1n/pp1p1p1p/4pn2/2p3p1/4P1P1/3P3P/PPP2P2/RQBBKRNN w FAfa - 0 9 +perft 1 22 +perft 2 633 +perft 3 14629 +perft 4 441809 +perft 5 10776416 +perft 6 335689685 + +id 1 +epd rqbkrbnn/p1ppp3/1p3pp1/7p/3P4/P1P5/1PQ1PPPP/R1BKRBNN w EAea - 0 9 +perft 1 32 +perft 2 607 +perft 3 20339 +perft 4 454319 +perft 5 15586203 +perft 6 383515709 + +id 1 +epd rqbkrnn1/pp2ppbp/3p4/2p3p1/2P5/1P3N1P/P2PPPP1/RQBKRN1B w EAea - 1 9 +perft 1 29 +perft 2 943 +perft 3 28732 +perft 4 908740 +perft 5 28761841 +perft 6 907579129 + +id 1 +epd rbqkb1nn/1ppppr1p/p5p1/5p2/1P6/2P4P/P1KPPPP1/RBQ1BRNN w a - 1 9 +perft 1 22 +perft 2 441 +perft 3 10403 +perft 4 231273 +perft 5 5784206 +perft 6 140934555 + +id 1 +epd rqkb1rnn/1pp1pp1p/p5p1/1b1p4/3P4/P5P1/RPP1PP1P/1QKBBRNN w Ffa - 1 9 +perft 1 21 +perft 2 505 +perft 3 11592 +perft 4 290897 +perft 5 7147063 +perft 6 188559137 + +id 1 +epd rq1rbbnn/pkp1ppp1/3p3p/1p2N1P1/8/8/PPPPPP1P/RQKRBB1N w DA - 0 9 +perft 1 27 +perft 2 608 +perft 3 16419 +perft 4 387751 +perft 5 10808908 +perft 6 268393274 + +id 1 +epd rqkrb2b/p2ppppp/2p3nn/1p6/5P2/PP1P4/2P1P1PP/RQKRBNNB w DAda - 1 9 +perft 1 30 +perft 2 749 +perft 3 21563 +perft 4 581531 +perft 5 16916813 +perft 6 485406712 + +id 1 +epd rbqkr1bn/pp1ppp2/2p1n2p/6p1/8/4BPNP/PPPPP1P1/RBQKRN2 w EAea - 0 9 +perft 1 23 +perft 2 600 +perft 3 15082 +perft 4 410057 +perft 5 11041820 +perft 6 314327867 + +id 1 +epd rqkbrnb1/2ppp1pp/pp3pn1/8/5P2/B2P4/PPP1P1PP/RQKBRN1N w EAea - 2 9 +perft 1 22 +perft 2 569 +perft 3 13541 +perft 4 371471 +perft 5 9395816 +perft 6 269460607 + +id 1 +epd rqkrnbb1/p1p1pppp/1p4n1/3p4/7P/P3P3/1PPPBPP1/RQKRN1BN w DAda - 0 9 +perft 1 27 +perft 2 579 +perft 3 15565 +perft 4 373079 +perft 5 10238486 +perft 6 266047417 + +id 1 +epd rqkrn1bb/p1ppp1pp/4n3/1p6/6p1/4N3/PPPPPPPP/RQKR2BB w DAda - 0 9 +perft 1 20 +perft 2 462 +perft 3 10234 +perft 4 274162 +perft 5 6563859 +perft 6 193376359 + +id 1 +epd bbrkqr2/pppp1ppp/6nn/8/2P1p3/3PP2N/PP3PPP/BBRKQR1N w FCfc - 0 9 +perft 1 28 +perft 2 724 +perft 3 21688 +perft 4 619064 +perft 5 19318355 +perft 6 593204629 + +id 1 +epd brk1qrnn/1pppbppp/4p3/8/1p6/P1P4P/3PPPP1/BRKBQRNN w FBfb - 1 9 +perft 1 24 +perft 2 662 +perft 3 16920 +perft 4 468215 +perft 5 12610387 +perft 6 355969349 + +id 1 +epd 1r1qrbnn/p1pkpppp/1p1p4/8/3P1PP1/P4b2/1PP1P2P/BRKQRBNN w EB - 1 9 +perft 1 22 +perft 2 696 +perft 3 17021 +perft 4 510247 +perft 5 13697382 +perft 6 401903030 + +id 1 +epd 1rkqrnnb/p1p1p1pp/1p1p4/3b1p1N/4P3/5N2/PPPP1PPP/BRKQR2B w EBeb - 1 9 +perft 1 29 +perft 2 887 +perft 3 27035 +perft 4 816176 +perft 5 26051242 +perft 6 791718847 + +id 1 +epd rbbkq1rn/pppppppp/7n/8/P7/3P3P/1PPKPPP1/RBB1QRNN w a - 3 9 +perft 1 22 +perft 2 417 +perft 3 9900 +perft 4 216855 +perft 5 5505063 +perft 6 134818483 + +id 1 +epd rkbbqr1n/1p1pppp1/2p2n2/p4NBp/8/3P4/PPP1PPPP/RK1BQRN1 w FAfa - 0 9 +perft 1 37 +perft 2 832 +perft 3 30533 +perft 4 728154 +perft 5 26676373 +perft 6 673756141 + +id 1 +epd rkbqrb1n/3pBppp/ppp2n2/8/8/P2P4/1PP1PPPP/RK1QRBNN w EAea - 0 9 +perft 1 28 +perft 2 685 +perft 3 19718 +perft 4 543069 +perft 5 16033316 +perft 6 482288814 + +id 1 +epd rkb1rn1b/ppppqppp/4p3/8/1P2n1P1/5Q2/P1PP1P1P/RKB1RNNB w EAea - 2 9 +perft 1 37 +perft 2 1158 +perft 3 40114 +perft 4 1234768 +perft 5 44672979 +perft 6 1389312729 + +id 1 +epd r1kqbrnn/pp1pp1p1/7p/2P2p2/5b2/3P4/P1P1P1PP/RBKQBRNN w FAfa - 0 9 +perft 1 5 +perft 2 161 +perft 3 4745 +perft 4 154885 +perft 5 4734999 +perft 6 157499039 + +id 1 +epd rkqbbr1n/ppp1ppp1/8/Q2p3p/4n3/3P1P2/PPP1P1PP/RK1BBRNN w FAfa - 2 9 +perft 1 38 +perft 2 1144 +perft 3 40433 +perft 4 1236877 +perft 5 43832975 +perft 6 1366087771 + +id 1 +epd rkqrbbn1/p1ppppp1/Bp5p/8/P6n/2P1P3/1P1P1PPP/RKQRB1NN w DAda - 0 9 +perft 1 28 +perft 2 551 +perft 3 15488 +perft 4 350861 +perft 5 9944107 +perft 6 251179183 + +id 1 +epd rkqrb1nb/1ppp1ppp/p7/4p3/5n2/3P2N1/PPPQPPPP/RK1RB1NB w DAda - 0 9 +perft 1 26 +perft 2 690 +perft 3 19877 +perft 4 513628 +perft 5 15965907 +perft 6 418191735 + +id 1 +epd rbkqrnbn/pppp1p2/4p1p1/7p/7P/P2P4/BPP1PPP1/R1KQRNBN w EAea - 0 9 +perft 1 27 +perft 2 515 +perft 3 13992 +perft 4 309727 +perft 5 8792550 +perft 6 218658292 + +id 1 +epd rkqbrnbn/pp1ppp2/8/2p3p1/P1P4p/5P2/1PKPP1PP/R1QBRNBN w ea - 0 9 +perft 1 27 +perft 2 627 +perft 3 16843 +perft 4 431101 +perft 5 11978698 +perft 6 328434174 + +id 1 +epd rkqrnbbn/1p2pp1p/3p2p1/p1p5/P5PP/3N4/1PPPPP2/RKQR1BBN w DAda - 0 9 +perft 1 23 +perft 2 624 +perft 3 15512 +perft 4 451860 +perft 5 11960861 +perft 6 367311176 + +id 1 +epd rk2rnbb/ppqppppp/2pn4/8/1P3P2/6P1/P1PPP1NP/RKQR1NBB w DAa - 1 9 +perft 1 27 +perft 2 727 +perft 3 20206 +perft 4 581003 +perft 5 16633696 +perft 6 505212747 + +id 1 +epd b1krrqnn/pp1ppp1p/2p3p1/8/P3Pb1P/1P6/2PP1PP1/BBRKRQNN w EC - 0 9 +perft 1 32 +perft 2 943 +perft 3 30759 +perft 4 865229 +perft 5 28672582 +perft 6 800922511 + +id 1 +epd 1rkbrqnn/p1pp1ppp/1p6/8/P2Pp3/8/1PPKPPQP/BR1BR1NN w eb - 0 9 +perft 1 28 +perft 2 916 +perft 3 24892 +perft 4 817624 +perft 5 22840279 +perft 6 759318058 + +id 1 +epd brkrqb1n/1pppp1pp/p7/3n1p2/P5P1/3PP3/1PP2P1P/BRKRQBNN w DBdb - 0 9 +perft 1 27 +perft 2 669 +perft 3 18682 +perft 4 484259 +perft 5 13956472 +perft 6 380267099 + +id 1 +epd brkrqnnb/3pppp1/1p6/p1p4p/2P3P1/6N1/PP1PPP1P/BRKRQ1NB w DBdb - 0 9 +perft 1 29 +perft 2 699 +perft 3 20042 +perft 4 512639 +perft 5 15093909 +perft 6 406594531 + +id 1 +epd r1bkrq1n/pp2pppp/3b1n2/2pp2B1/6P1/3P1P2/PPP1P2P/RB1KRQNN w EAea - 2 9 +perft 1 27 +perft 2 835 +perft 3 22848 +perft 4 713550 +perft 5 19867800 +perft 6 631209313 + +id 1 +epd rk1brq1n/p1p1pppp/3p1n2/1p3b2/4P3/2NQ4/PPPP1PPP/RKBBR2N w EAea - 4 9 +perft 1 36 +perft 2 1004 +perft 3 35774 +perft 4 979608 +perft 5 35143142 +perft 6 966310885 + +id 1 +epd rkbrqbnn/1p2ppp1/B1p5/p2p3p/4P2P/8/PPPP1PP1/RKBRQ1NN w DAda - 0 9 +perft 1 27 +perft 2 748 +perft 3 21005 +perft 4 597819 +perft 5 17597073 +perft 6 515304215 + +id 1 +epd rkbrqn1b/pp1pp1pp/2p2p2/5n2/8/2P2P2/PP1PP1PP/RKBRQ1NB w DAda - 0 9 +perft 1 20 +perft 2 479 +perft 3 10485 +perft 4 266446 +perft 5 6253775 +perft 6 167767913 + +id 1 +epd rbkrbnn1/ppppp1pp/5q2/5p2/5P2/P3P2N/1PPP2PP/RBKRBQ1N w DAda - 3 9 +perft 1 28 +perft 2 947 +perft 3 26900 +perft 4 876068 +perft 5 26007841 +perft 6 838704143 + +id 1 +epd rkr1bqnn/1ppp1p1p/p5p1/4p3/3PP2b/2P2P2/PP4PP/RKRBBQNN w CAca - 0 9 +perft 1 31 +perft 2 1004 +perft 3 32006 +perft 4 1006830 +perft 5 32688124 +perft 6 1024529879 + +id 1 +epd rkrqbbnn/pppp3p/8/4ppp1/1PP4P/8/P2PPPP1/RKRQBBNN w CAca - 0 9 +perft 1 24 +perft 2 717 +perft 3 18834 +perft 4 564137 +perft 5 15844525 +perft 6 484884485 + +id 1 +epd rkrqbn1b/pppp2pp/8/4pp2/1P1P2n1/5N2/P1P1PP1P/RKRQBN1B w CAca - 0 9 +perft 1 25 +perft 2 718 +perft 3 19654 +perft 4 587666 +perft 5 17257753 +perft 6 537354146 + +id 1 +epd rbkrqnbn/p1p1ppp1/1p1p4/8/3PP2p/2PB4/PP3PPP/R1KRQNBN w DAda - 0 9 +perft 1 30 +perft 2 754 +perft 3 23298 +perft 4 611322 +perft 5 19338246 +perft 6 532603566 + +id 1 +epd 1krbqnbn/1p2pppp/r1pp4/p7/8/1P1P2PP/P1P1PP2/RKRBQNBN w CAc - 0 9 +perft 1 21 +perft 2 566 +perft 3 13519 +perft 4 375128 +perft 5 9700847 +perft 6 279864836 + +id 1 +epd rkrq1b2/pppppppb/3n2np/2N5/4P3/7P/PPPP1PP1/RKRQ1BBN w CAca - 1 9 +perft 1 33 +perft 2 654 +perft 3 21708 +perft 4 479678 +perft 5 15990307 +perft 6 382218272 + +id 1 +epd rkr1nnbb/ppp2p1p/3p1qp1/4p3/P5P1/3PN3/1PP1PP1P/RKRQN1BB w CAca - 1 9 +perft 1 28 +perft 2 715 +perft 3 20361 +perft 4 555328 +perft 5 16303092 +perft 6 468666425 + +id 1 +epd bbrkrnqn/1p1ppppp/8/8/p2pP3/PP6/2P2PPP/BBRKRNQN w ECec - 0 9 +perft 1 24 +perft 2 757 +perft 3 19067 +perft 4 603231 +perft 5 15957628 +perft 6 509307623 + +id 1 +epd brkbrnqn/ppp2p2/4p3/P2p2pp/6P1/5P2/1PPPP2P/BRKBRNQN w EBeb - 0 9 +perft 1 25 +perft 2 548 +perft 3 14563 +perft 4 348259 +perft 5 9688526 +perft 6 247750144 + +id 1 +epd brkr1bqn/1pppppp1/3n3p/1p6/P7/4P1P1/1PPP1P1P/BRKRN1QN w DBdb - 0 9 +perft 1 19 +perft 2 359 +perft 3 7430 +perft 4 157099 +perft 5 3521652 +perft 6 81787718 + +id 1 +epd brkr1qnb/pppp2pp/2B1p3/5p2/2n5/6PP/PPPPPPN1/BRKR1QN1 w DBdb - 1 9 +perft 1 27 +perft 2 854 +perft 3 23303 +perft 4 741626 +perft 5 20558538 +perft 6 667089231 + +id 1 +epd rbbkrnqn/p1p1p1pp/8/1p1p4/1P1Pp3/6N1/P1P2PPP/RBBKRNQ1 w EAea - 0 9 +perft 1 28 +perft 2 723 +perft 3 19844 +perft 4 514440 +perft 5 14621108 +perft 6 397454100 + +id 1 +epd rkbbrn1n/pppppp2/5q1p/6p1/3P3P/4P3/PPP2PP1/RKBBRNQN w EAea - 1 9 +perft 1 25 +perft 2 741 +perft 3 19224 +perft 4 585198 +perft 5 15605840 +perft 6 485037906 + +id 1 +epd rkbr1bq1/ppnppppp/6n1/2p5/2P1N2P/8/PP1PPPP1/RKBRNBQ1 w DAda - 3 9 +perft 1 24 +perft 2 547 +perft 3 14359 +perft 4 339497 +perft 5 9410221 +perft 6 234041078 + +id 1 +epd 1kbrnqnb/r1ppppp1/8/pp5p/8/1P1NP3/P1PP1PPP/RKB1RQNB w Ad - 2 9 +perft 1 26 +perft 2 618 +perft 3 17305 +perft 4 442643 +perft 5 13112297 +perft 6 357030697 + +id 1 +epd rbkrb1qn/1pp1ppp1/3pn2p/pP6/8/4N1P1/P1PPPP1P/RBKRB1QN w DAda - 0 9 +perft 1 21 +perft 2 544 +perft 3 12492 +perft 4 338832 +perft 5 8381483 +perft 6 236013157 + +id 1 +epd rkrbbnqn/ppppp3/5p2/6pp/5PBP/4P3/PPPP2P1/RKR1BNQN w CAca - 0 9 +perft 1 30 +perft 2 891 +perft 3 25435 +perft 4 764356 +perft 5 21894752 +perft 6 669256602 + +id 1 +epd rkr1bb1n/ppppp1pp/5p2/4n3/3QP3/5P2/RPPP2PP/1KRNBB1N w Cca - 1 9 +perft 1 45 +perft 2 1172 +perft 3 51766 +perft 4 1332060 +perft 5 57856784 +perft 6 1501852662 + +id 1 +epd rkr1bqnb/pp1ppppp/8/2pN4/1P6/5N2/P1PPnPPP/RKR1BQ1B w CAca - 0 9 +perft 1 28 +perft 2 730 +perft 3 20511 +perft 4 559167 +perft 5 16323242 +perft 6 463032124 + +id 1 +epd rbkrnqb1/2ppppp1/p5np/1p6/8/3N4/PPPPPPPP/RBKRQNB1 w DAda - 2 9 +perft 1 20 +perft 2 417 +perft 3 9159 +perft 4 217390 +perft 5 5180716 +perft 6 133936564 + +id 1 +epd rkrbnqb1/p1pppnpp/5p2/1p6/2P5/1P1P1N2/P3PPPP/RKRB1QBN w CAca - 0 9 +perft 1 25 +perft 2 546 +perft 3 14039 +perft 4 330316 +perft 5 8813781 +perft 6 222026485 + +id 1 +epd rkr1qbbn/ppppppp1/4n3/7p/8/P7/KPPPPPPP/R1RNQBBN w ca - 0 9 +perft 1 22 +perft 2 484 +perft 3 11458 +perft 4 267495 +perft 5 6633319 +perft 6 163291279 + +id 1 +epd rkrnqnb1/1ppppp2/p5p1/7p/8/P1bPP3/1PP1QPPP/RKRN1NBB w CAca - 0 9 +perft 1 22 +perft 2 636 +perft 3 15526 +perft 4 441001 +perft 5 11614241 +perft 6 331083405 + +id 1 +epd b2krn1q/p1rppppp/1Q3n2/2p1b3/1P4P1/8/P1PPPP1P/BBRKRNN1 w ECe - 3 9 +perft 1 36 +perft 2 1192 +perft 3 42945 +perft 4 1406795 +perft 5 50382104 +perft 6 1650202838 + +id 1 +epd brkbrnn1/pp1pppp1/7q/2p5/6Pp/4P1NP/PPPP1P2/BRKBR1NQ w EBeb - 2 9 +perft 1 30 +perft 2 978 +perft 3 29593 +perft 4 942398 +perft 5 29205057 +perft 6 936568065 + +id 1 +epd brkrnb1q/pp1p1ppp/2p1p3/5n2/1P6/5N1N/P1PPPPPP/BRKR1B1Q w DBdb - 1 9 +perft 1 31 +perft 2 897 +perft 3 27830 +perft 4 810187 +perft 5 25423729 +perft 6 755334868 + +id 1 +epd brkr1nqb/pp1p1pp1/2pn3p/P3p3/4P3/6P1/1PPP1P1P/BRKRNNQB w DBdb - 0 9 +perft 1 19 +perft 2 382 +perft 3 8052 +perft 4 182292 +perft 5 4232274 +perft 6 103537333 + +id 1 +epd r1bkrn1q/ppbppppp/5n2/2p5/3P4/P6N/1PP1PPPP/RBBKRNQ1 w EAea - 3 9 +perft 1 27 +perft 2 822 +perft 3 22551 +perft 4 678880 +perft 5 19115128 +perft 6 578210135 + +id 1 +epd rkbbrnnq/pp2pppp/8/2pp4/P1P5/1P3P2/3PP1PP/RKBBRNNQ w EAea - 1 9 +perft 1 23 +perft 2 643 +perft 3 15410 +perft 4 442070 +perft 5 11170489 +perft 6 329615708 + +id 1 +epd rkbr1b1q/p1pppppp/1p1n4/7n/5QP1/3N4/PPPPPP1P/RKBR1BN1 w DAda - 4 9 +perft 1 37 +perft 2 943 +perft 3 34382 +perft 4 880474 +perft 5 31568111 +perft 6 842265141 + +id 1 +epd rkbr1nqb/pppp2np/8/4ppp1/1P6/6N1/P1PPPPPP/RKBRN1QB w DAda - 1 9 +perft 1 23 +perft 2 574 +perft 3 13260 +perft 4 362306 +perft 5 9020291 +perft 6 261247606 + +id 1 +epd rbkr1nnq/p1p1pp1p/1p4p1/3p4/b3P3/4N3/PPPPNPPP/RBKRB1Q1 w DAda - 0 9 +perft 1 26 +perft 2 900 +perft 3 23414 +perft 4 805006 +perft 5 21653203 +perft 6 745802405 + +id 1 +epd rkrbb1nq/p2pppp1/1p4n1/2p4p/3N4/4P1P1/PPPP1P1P/RKRBBN1Q w CAca - 0 9 +perft 1 32 +perft 2 697 +perft 3 22231 +perft 4 531121 +perft 5 17150175 +perft 6 441578567 + +id 1 +epd rkrnbb1q/pp2pp1p/6pn/2pp4/2B1P2P/8/PPPP1PP1/RKRNB1NQ w CAca - 0 9 +perft 1 28 +perft 2 854 +perft 3 23853 +perft 4 755990 +perft 5 21823412 +perft 6 712787248 + +id 1 +epd rk2bnqb/pprpppp1/4n2p/2p5/P7/3P2NP/1PP1PPP1/RKRNB1QB w CAa - 1 9 +perft 1 26 +perft 2 596 +perft 3 16251 +perft 4 414862 +perft 5 11758184 +perft 6 323043654 + +id 1 +epd r1krnnbq/pp1ppp1p/6p1/2p5/2P5/P3P3/Rb1P1PPP/1BKRNNBQ w Dda - 0 9 +perft 1 2 +perft 2 61 +perft 3 1312 +perft 4 40072 +perft 5 937188 +perft 6 28753562 + +id 1 +epd 1krbnnbq/1pp1p1pp/r7/p2p1p2/3PP3/2P3P1/PP3P1P/RKRBNNBQ w CAc - 0 9 +perft 1 30 +perft 2 953 +perft 3 28033 +perft 4 860530 +perft 5 25531358 +perft 6 787205262 + +id 1 +epd rkr1nbbq/2ppp1pp/1pn5/p4p2/P6P/3P4/1PP1PPPB/RKRNNB1Q w CAca - 1 9 +perft 1 24 +perft 2 645 +perft 3 15689 +perft 4 446423 +perft 5 11484012 +perft 6 341262639 + +id 1 +epd rkrnnqbb/p1ppp2p/Qp6/4Pp2/5p2/8/PPPP2PP/RKRNN1BB w CAca - 0 9 +perft 1 35 +perft 2 929 +perft 3 32020 +perft 4 896130 +perft 5 31272517 +perft 6 915268405 + +id 1 +epd bbq1nr1r/pppppk1p/2n2p2/6p1/P4P2/4P1P1/1PPP3P/BBQNNRKR w HF - 1 9 +perft 1 23 +perft 2 589 +perft 3 14744 +perft 4 387556 +perft 5 10316716 +perft 6 280056112 From 57c9f87cbf8d57d13dce787fe243500adac4a67c Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 20 Jan 2023 21:56:17 +0100 Subject: [PATCH 011/250] Fix ids in chess960.perft --- examples/perft/chess960.perft | 1919 +++++++++++++++++---------------- 1 file changed, 960 insertions(+), 959 deletions(-) diff --git a/examples/perft/chess960.perft b/examples/perft/chess960.perft index 0d14d5da0..76be26eed 100644 --- a/examples/perft/chess960.perft +++ b/examples/perft/chess960.perft @@ -1,6 +1,7 @@ # https://www.chessprogramming.org/Chess960_Perft_Results +# https://github.com/AndyGrant/Ethereal/blob/master/src/perft/fischer.epd -id 1 +id 0 epd bqnb1rkr/pp3ppp/3ppn2/2p5/5P2/P2P4/NPP1P1PP/BQ1BNRKR w HFhf - 2 9 perft 1 21 perft 2 528 @@ -18,7 +19,7 @@ perft 4 667366 perft 5 16253601 perft 6 590751109 -id 1 +id 2 epd b1q1rrkb/pppppppp/3nn3/8/P7/1PPP4/4PPPP/BQNNRKRB w GE - 1 9 perft 1 20 perft 2 479 @@ -27,7 +28,7 @@ perft 4 273318 perft 5 6417013 perft 6 177654692 -id 1 +id 3 epd qbbnnrkr/2pp2pp/p7/1p2pp2/8/P3PP2/1PPP1KPP/QBBNNR1R w hf - 0 9 perft 1 22 perft 2 593 @@ -36,7 +37,7 @@ perft 4 382958 perft 5 9183776 perft 6 274103539 -id 1 +id 4 epd 1nbbnrkr/p1p1ppp1/3p4/1p3P1p/3Pq2P/8/PPP1P1P1/QNBBNRKR w HFhf - 0 9 perft 1 28 perft 2 1120 @@ -45,7 +46,7 @@ perft 4 1171749 perft 5 34030312 perft 6 1250970898 -id 1 +id 5 epd qnbnr1kr/ppp1b1pp/4p3/3p1p2/8/2NPP3/PPP1BPPP/QNB1R1KR w HEhe - 1 9 perft 1 29 perft 2 899 @@ -54,7 +55,7 @@ perft 4 824055 perft 5 24851983 perft 6 775718317 -id 1 +id 6 epd q1bnrkr1/ppppp2p/2n2p2/4b1p1/2NP4/8/PPP1PPPP/QNB1RRKB w ge - 1 9 perft 1 30 perft 2 860 @@ -63,7 +64,7 @@ perft 4 732757 perft 5 21093346 perft 6 649209803 -id 1 +id 7 epd qbn1brkr/ppp1p1p1/2n4p/3p1p2/P7/6PP/QPPPPP2/1BNNBRKR w HFhf - 0 9 perft 1 25 perft 2 635 @@ -72,7 +73,7 @@ perft 4 465806 perft 5 13203304 perft 6 377184252 -id 1 +id 8 epd qnnbbrkr/1p2ppp1/2pp3p/p7/1P5P/2NP4/P1P1PPP1/Q1NBBRKR w HFhf - 0 9 perft 1 24 perft 2 572 @@ -81,7 +82,7 @@ perft 4 384260 perft 5 11110203 perft 6 293989890 -id 1 +id 9 epd qn1rbbkr/ppp2p1p/1n1pp1p1/8/3P4/P6P/1PP1PPPK/QNNRBB1R w hd - 2 9 perft 1 28 perft 2 811 @@ -90,7 +91,7 @@ perft 4 679699 perft 5 19836606 perft 6 594527992 -id 1 +id 10 epd qnr1bkrb/pppp2pp/3np3/5p2/8/P2P2P1/NPP1PP1P/QN1RBKRB w GDg - 3 9 perft 1 33 perft 2 823 @@ -99,7 +100,7 @@ perft 4 713420 perft 5 23114629 perft 6 646390782 -id 1 +id 11 epd qb1nrkbr/1pppp1p1/1n3p2/p1B4p/8/3P1P1P/PPP1P1P1/QBNNRK1R w HEhe - 0 9 perft 1 31 perft 2 855 @@ -108,7 +109,7 @@ perft 4 735703 perft 5 21796206 perft 6 651054626 -id 1 +id 12 epd qnnbrk1r/1p1ppbpp/2p5/p4p2/2NP3P/8/PPP1PPP1/Q1NBRKBR w HEhe - 0 9 perft 1 26 perft 2 790 @@ -117,7 +118,7 @@ perft 4 642367 perft 5 17819770 perft 6 544866674 -id 1 +id 13 epd 1qnrkbbr/1pppppp1/p1n4p/8/P7/1P1N1P2/2PPP1PP/QN1RKBBR w HDhd - 0 9 perft 1 37 perft 2 883 @@ -126,7 +127,7 @@ perft 4 815535 perft 5 29370838 perft 6 783201510 -id 1 +id 14 epd qn1rkrbb/pp1p1ppp/2p1p3/3n4/4P2P/2NP4/PPP2PP1/Q1NRKRBB w FDfd - 1 9 perft 1 24 perft 2 585 @@ -135,7 +136,7 @@ perft 4 356950 perft 5 9482310 perft 6 233468620 -id 1 +id 15 epd bb1qnrkr/pp1p1pp1/1np1p3/4N2p/8/1P4P1/P1PPPP1P/BBNQ1RKR w HFhf - 0 9 perft 1 29 perft 2 864 @@ -144,7 +145,7 @@ perft 4 799727 perft 5 24219627 perft 6 776836316 -id 1 +id 16 epd bnqbnr1r/p1p1ppkp/3p4/1p4p1/P7/3NP2P/1PPP1PP1/BNQB1RKR w HF - 0 9 perft 1 26 perft 2 889 @@ -153,7 +154,7 @@ perft 4 832956 perft 5 23701014 perft 6 809194268 -id 1 +id 17 epd bnqnrbkr/1pp2pp1/p7/3pP2p/4P1P1/8/PPPP3P/BNQNRBKR w HEhe d6 0 9 perft 1 31 perft 2 984 @@ -162,7 +163,7 @@ perft 4 962591 perft 5 29032175 perft 6 1008880643 -id 1 +id 18 epd b1qnrrkb/ppp1pp1p/n2p1Pp1/8/8/P7/1PPPP1PP/BNQNRKRB w GE - 0 9 perft 1 20 perft 2 484 @@ -171,7 +172,7 @@ perft 4 281606 perft 5 6718715 perft 6 193594729 -id 1 +id 19 epd n1bqnrkr/pp1ppp1p/2p5/6p1/2P2b2/PN6/1PNPPPPP/1BBQ1RKR w HFhf - 2 9 perft 1 23 perft 2 732 @@ -180,7 +181,7 @@ perft 4 558191 perft 5 14481581 perft 6 457140569 -id 1 +id 20 epd n1bb1rkr/qpnppppp/2p5/p7/P1P5/5P2/1P1PPRPP/NQBBN1KR w Hhf - 1 9 perft 1 27 perft 2 697 @@ -189,7 +190,7 @@ perft 4 505089 perft 5 14226907 perft 6 400942568 -id 1 +id 21 epd nqb1rbkr/pppppp1p/4n3/6p1/4P3/1NP4P/PP1P1PP1/1QBNRBKR w HEhe - 1 9 perft 1 28 perft 2 641 @@ -198,7 +199,7 @@ perft 4 456916 perft 5 13780398 perft 6 354122358 -id 1 +id 22 epd n1bnrrkb/pp1pp2p/2p2p2/6p1/5B2/3P4/PPP1PPPP/NQ1NRKRB w GE - 2 9 perft 1 28 perft 2 606 @@ -207,7 +208,7 @@ perft 4 381646 perft 5 10815324 perft 6 254026570 -id 1 +id 23 epd nbqnbrkr/2ppp1p1/pp3p1p/8/4N2P/1N6/PPPPPPP1/1BQ1BRKR w HFhf - 0 9 perft 1 26 perft 2 626 @@ -216,7 +217,7 @@ perft 4 437525 perft 5 12719546 perft 6 339132046 -id 1 +id 24 epd nq1bbrkr/pp2nppp/2pp4/4p3/1PP1P3/1B6/P2P1PPP/NQN1BRKR w HFhf - 2 9 perft 1 21 perft 2 504 @@ -225,7 +226,7 @@ perft 4 302230 perft 5 7697880 perft 6 207028745 -id 1 +id 25 epd nqnrb1kr/2pp1ppp/1p1bp3/p1B5/5P2/3N4/PPPPP1PP/NQ1R1BKR w HDhd - 0 9 perft 1 30 perft 2 672 @@ -234,7 +235,7 @@ perft 4 465317 perft 5 13454573 perft 6 345445468 -id 1 +id 26 epd nqn2krb/p1prpppp/1pbp4/7P/5P2/8/PPPPPKP1/NQNRB1RB w g - 3 9 perft 1 21 perft 2 461 @@ -243,7 +244,7 @@ perft 4 248069 perft 5 6194124 perft 6 152861936 -id 1 +id 27 epd nb1n1kbr/ppp1rppp/3pq3/P3p3/8/4P3/1PPPRPPP/NBQN1KBR w Hh - 1 9 perft 1 19 perft 2 566 @@ -252,7 +253,7 @@ perft 4 358337 perft 5 8047916 perft 6 249171636 -id 1 +id 28 epd nqnbrkbr/1ppppp1p/p7/6p1/6P1/P6P/1PPPPP2/NQNBRKBR w HEhe - 1 9 perft 1 20 perft 2 382 @@ -261,7 +262,7 @@ perft 4 187263 perft 5 4708975 perft 6 112278808 -id 1 +id 29 epd nq1rkb1r/pp1pp1pp/1n2bp1B/2p5/8/5P1P/PPPPP1P1/NQNRKB1R w HDhd - 2 9 perft 1 24 perft 2 809 @@ -270,7 +271,7 @@ perft 4 673811 perft 5 17647882 perft 6 593457788 -id 1 +id 30 epd nqnrkrb1/pppppp2/7p/4b1p1/8/PN1NP3/1PPP1PPP/1Q1RKRBB w FDfd - 1 9 perft 1 26 perft 2 683 @@ -279,7 +280,7 @@ perft 4 473911 perft 5 13055173 perft 6 352398011 -id 1 +id 31 epd bb1nqrkr/1pp1ppp1/pn5p/3p4/8/P2NNP2/1PPPP1PP/BB2QRKR w HFhf - 0 9 perft 1 29 perft 2 695 @@ -288,7 +289,7 @@ perft 4 552634 perft 5 17454857 perft 6 483785639 -id 1 +id 32 epd bnn1qrkr/pp1ppp1p/2p5/b3Q1p1/8/5P1P/PPPPP1P1/BNNB1RKR w HFhf - 2 9 perft 1 44 perft 2 920 @@ -297,7 +298,7 @@ perft 4 795317 perft 5 29742670 perft 6 702867204 -id 1 +id 33 epd bnnqrbkr/pp1p2p1/2p1p2p/5p2/1P5P/1R6/P1PPPPP1/BNNQRBK1 w Ehe - 0 9 perft 1 33 perft 2 1022 @@ -306,7 +307,7 @@ perft 4 1024721 perft 5 32898113 perft 6 1047360456 -id 1 +id 34 epd b1nqrkrb/2pppppp/p7/1P6/1n6/P4P2/1P1PP1PP/BNNQRKRB w GEge - 0 9 perft 1 23 perft 2 638 @@ -315,7 +316,7 @@ perft 4 446539 perft 5 11735969 perft 6 344211589 -id 1 +id 35 epd n1bnqrkr/3ppppp/1p6/pNp1b3/2P3P1/8/PP1PPP1P/NBB1QRKR w HFhf - 1 9 perft 1 29 perft 2 728 @@ -324,7 +325,7 @@ perft 4 532084 perft 5 15621236 perft 6 415766465 -id 1 +id 36 epd n2bqrkr/p1p1pppp/1pn5/3p1b2/P6P/1NP5/1P1PPPP1/1NBBQRKR w HFhf - 3 9 perft 1 20 perft 2 533 @@ -333,7 +334,7 @@ perft 4 325059 perft 5 8088751 perft 6 223068417 -id 1 +id 37 epd nnbqrbkr/1pp1p1p1/p2p4/5p1p/2P1P3/N7/PPQP1PPP/N1B1RBKR w HEhe - 0 9 perft 1 27 perft 2 619 @@ -342,7 +343,7 @@ perft 4 444421 perft 5 13755384 perft 6 357222394 -id 1 +id 38 epd nnbqrkr1/pp1pp2p/2p2b2/5pp1/1P5P/4P1P1/P1PP1P2/NNBQRKRB w GEge - 1 9 perft 1 32 perft 2 1046 @@ -351,7 +352,7 @@ perft 4 1111186 perft 5 36218182 perft 6 1202830851 -id 1 +id 39 epd nb1qbrkr/p1pppp2/1p1n2pp/8/1P6/2PN3P/P2PPPP1/NB1QBRKR w HFhf - 0 9 perft 1 25 perft 2 521 @@ -360,7 +361,7 @@ perft 4 306427 perft 5 8697700 perft 6 201455191 -id 1 +id 40 epd nnq1brkr/pp1pppp1/8/2p4P/8/5K2/PPPbPP1P/NNQBBR1R w hf - 0 9 perft 1 23 perft 2 724 @@ -369,7 +370,7 @@ perft 4 571072 perft 5 15338230 perft 6 484638597 -id 1 +id 41 epd nnqrbb1r/pppppk2/5pp1/7p/1P6/3P2PP/P1P1PP2/NNQRBBKR w HD - 0 9 perft 1 30 perft 2 717 @@ -378,7 +379,7 @@ perft 4 547145 perft 5 17166700 perft 6 450069742 -id 1 +id 42 epd nnqr1krb/p1p1pppp/2bp4/8/1p1P4/4P3/PPP2PPP/NNQRBKRB w GDgd - 0 9 perft 1 25 perft 2 873 @@ -387,7 +388,7 @@ perft 4 728628 perft 5 18162741 perft 6 641708630 -id 1 +id 43 epd nbnqrkbr/p2ppp2/1p4p1/2p4p/3P3P/3N4/PPP1PPPR/NB1QRKB1 w Ehe - 0 9 perft 1 24 perft 2 589 @@ -396,7 +397,7 @@ perft 4 382317 perft 5 10630667 perft 6 279474189 -id 1 +id 44 epd n1qbrkbr/p1ppp2p/2n2pp1/1p6/1P6/2P3P1/P2PPP1P/NNQBRKBR w HEhe - 0 9 perft 1 22 perft 2 592 @@ -405,7 +406,7 @@ perft 4 401976 perft 5 10356818 perft 6 301583306 -id 1 +id 45 epd 2qrkbbr/ppn1pppp/n1p5/3p4/5P2/P1PP4/1P2P1PP/NNQRKBBR w HDhd - 1 9 perft 1 27 perft 2 750 @@ -414,7 +415,7 @@ perft 4 605458 perft 5 16819085 perft 6 516796736 -id 1 +id 46 epd 1nqr1rbb/pppkp1pp/1n3p2/3p4/1P6/5P1P/P1PPPKP1/NNQR1RBB w - - 1 9 perft 1 24 perft 2 623 @@ -423,7 +424,7 @@ perft 4 429446 perft 5 11594634 perft 6 322745925 -id 1 +id 47 epd bbn1rqkr/pp1pp2p/4npp1/2p5/1P6/2BPP3/P1P2PPP/1BNNRQKR w HEhe - 0 9 perft 1 23 perft 2 730 @@ -432,7 +433,7 @@ perft 4 565340 perft 5 14496370 perft 6 468608864 -id 1 +id 48 epd bn1brqkr/pppp2p1/3npp2/7p/PPP5/8/3PPPPP/BNNBRQKR w HEhe - 0 9 perft 1 25 perft 2 673 @@ -441,7 +442,7 @@ perft 4 513696 perft 5 14284338 perft 6 434008567 -id 1 +id 49 epd bn1rqbkr/ppp1ppp1/1n6/2p4p/7P/3P4/PPP1PPP1/BN1RQBKR w HDhd - 0 9 perft 1 25 perft 2 776 @@ -450,7 +451,7 @@ perft 4 660217 perft 5 18486027 perft 6 616653869 -id 1 +id 50 epd bnnr1krb/ppp2ppp/3p4/3Bp3/q1P3PP/8/PP1PPP2/BNNRQKR1 w GDgd - 0 9 perft 1 29 perft 2 1040 @@ -459,7 +460,7 @@ perft 4 1053113 perft 5 31801525 perft 6 1075147725 -id 1 +id 51 epd 1bbnrqkr/pp1ppppp/8/2p5/n7/3PNPP1/PPP1P2P/NBB1RQKR w HEhe - 1 9 perft 1 24 perft 2 598 @@ -468,7 +469,7 @@ perft 4 409766 perft 5 11394778 perft 6 310589129 -id 1 +id 52 epd nnbbrqkr/p2ppp1p/1pp5/8/6p1/N1P5/PPBPPPPP/N1B1RQKR w HEhe - 0 9 perft 1 26 perft 2 530 @@ -477,7 +478,7 @@ perft 4 326312 perft 5 8846766 perft 6 229270702 -id 1 +id 53 epd nnbrqbkr/2p1p1pp/p4p2/1p1p4/8/NP6/P1PPPPPP/N1BRQBKR w HDhd - 0 9 perft 1 17 perft 2 496 @@ -486,7 +487,7 @@ perft 4 303310 perft 5 7103549 perft 6 217108001 -id 1 +id 54 epd nnbrqk1b/pp2pprp/2pp2p1/8/3PP1P1/8/PPP2P1P/NNBRQRKB w d - 1 9 perft 1 33 perft 2 820 @@ -495,7 +496,7 @@ perft 4 706784 perft 5 24714401 perft 6 645835197 -id 1 +id 55 epd 1bnrbqkr/ppnpp1p1/2p2p1p/8/1P6/4PPP1/P1PP3P/NBNRBQKR w HDhd - 0 9 perft 1 27 perft 2 705 @@ -504,7 +505,7 @@ perft 4 548680 perft 5 15964771 perft 6 464662032 -id 1 +id 56 epd n1rbbqkr/pp1pppp1/7p/P1p5/1n6/2PP4/1P2PPPP/NNRBBQKR w HChc - 0 9 perft 1 22 perft 2 631 @@ -513,7 +514,7 @@ perft 4 431801 perft 5 10911545 perft 6 320838556 -id 1 +id 57 epd n1rqb1kr/p1pppp1p/1pn4b/3P2p1/P7/1P6/2P1PPPP/NNRQBBKR w HChc - 0 9 perft 1 24 perft 2 477 @@ -522,7 +523,7 @@ perft 4 263189 perft 5 7419372 perft 6 165945904 -id 1 +id 58 epd nnrqbkrb/pppp1pp1/7p/4p3/6P1/2N2B2/PPPPPP1P/NR1QBKR1 w Ggc - 2 9 perft 1 29 perft 2 658 @@ -531,7 +532,7 @@ perft 4 476620 perft 5 14233587 perft 6 373744834 -id 1 +id 59 epd n1nrqkbr/ppb2ppp/3pp3/2p5/2P3P1/5P2/PP1PPB1P/NBNRQK1R w HDhd - 1 9 perft 1 32 perft 2 801 @@ -540,7 +541,7 @@ perft 4 681428 perft 5 22318948 perft 6 619857455 -id 1 +id 60 epd 2rbqkbr/p1pppppp/1nn5/1p6/7P/P4P2/1PPPP1PB/NNRBQK1R w HChc - 2 9 perft 1 27 perft 2 647 @@ -549,7 +550,7 @@ perft 4 458057 perft 5 13189156 perft 6 354689323 -id 1 +id 61 epd nn1qkbbr/pp2ppp1/2rp4/2p4p/P2P4/1N5P/1PP1PPP1/1NRQKBBR w HCh - 1 9 perft 1 24 perft 2 738 @@ -558,7 +559,7 @@ perft 4 586009 perft 5 16420659 perft 6 519075930 -id 1 +id 62 epd nnrqk1bb/p1ppp2p/5rp1/1p3p2/1P4P1/5P1P/P1PPP3/NNRQKRBB w FCc - 1 9 perft 1 25 perft 2 795 @@ -567,7 +568,7 @@ perft 4 648945 perft 5 17342527 perft 6 556144017 -id 1 +id 63 epd bb1nrkqr/ppppn2p/4ppp1/8/1P4P1/4P3/P1PPKP1P/BBNNR1QR w he - 0 9 perft 1 29 perft 2 664 @@ -576,7 +577,7 @@ perft 4 498376 perft 5 15373803 perft 6 406016364 -id 1 +id 64 epd bnnbrkqr/1p1ppp2/8/p1p3pp/1P6/N4P2/PBPPP1PP/2NBRKQR w HEhe - 0 9 perft 1 31 perft 2 770 @@ -585,7 +586,7 @@ perft 4 677212 perft 5 22562080 perft 6 662029574 -id 1 +id 65 epd 1nnrkbqr/p1pp1ppp/4p3/1p6/1Pb1P3/6PB/P1PP1P1P/BNNRK1QR w HDhd - 0 9 perft 1 27 perft 2 776 @@ -594,7 +595,7 @@ perft 4 641002 perft 5 19153245 perft 6 562738257 -id 1 +id 66 epd bnr1kqrb/pppp1pp1/1n5p/4p3/P3P3/3P2P1/1PP2P1P/BNNRKQRB w GDg - 0 9 perft 1 26 perft 2 624 @@ -603,7 +604,7 @@ perft 4 435426 perft 5 11906515 perft 6 338092952 -id 1 +id 67 epd nbbnrkqr/p1ppp1pp/1p3p2/8/2P5/4P3/PP1P1PPP/NBBNRKQR w HEhe - 1 9 perft 1 25 perft 2 624 @@ -612,7 +613,7 @@ perft 4 419635 perft 5 10817378 perft 6 311138112 -id 1 +id 68 epd nn1brkqr/pp1bpppp/8/2pp4/P4P2/1PN5/2PPP1PP/N1BBRKQR w HEhe - 1 9 perft 1 23 perft 2 659 @@ -621,7 +622,7 @@ perft 4 476567 perft 5 13242252 perft 6 373557073 -id 1 +id 69 epd n1brkbqr/ppp1pp1p/6pB/3p4/2Pn4/8/PP2PPPP/NN1RKBQR w HDhd - 0 9 perft 1 32 perft 2 1026 @@ -630,7 +631,7 @@ perft 4 978278 perft 5 29436320 perft 6 957904151 -id 1 +id 70 epd nnbrkqrb/p2ppp2/Q5pp/1pp5/4PP2/2N5/PPPP2PP/N1BRK1RB w GDgd - 0 9 perft 1 36 perft 2 843 @@ -639,7 +640,7 @@ perft 4 715537 perft 5 24321197 perft 6 630396940 -id 1 +id 71 epd nbnrbk1r/pppppppq/8/7p/8/1N2QPP1/PPPPP2P/NB1RBK1R w HDhd - 2 9 perft 1 36 perft 2 973 @@ -648,7 +649,7 @@ perft 4 1018054 perft 5 37143354 perft 6 1124883780 -id 1 +id 72 epd nnrbbkqr/2pppp1p/p7/6p1/1p2P3/4QPP1/PPPP3P/NNRBBK1R w HChc - 0 9 perft 1 36 perft 2 649 @@ -657,7 +658,7 @@ perft 4 489526 perft 5 16836636 perft 6 416139320 -id 1 +id 73 epd nnrkbbqr/1p2pppp/p2p4/2p5/8/1N2P1P1/PPPP1P1P/1NKRBBQR w hc - 0 9 perft 1 26 perft 2 672 @@ -666,7 +667,7 @@ perft 4 477801 perft 5 13342771 perft 6 363074681 -id 1 +id 74 epd n1rkbqrb/pp1ppp2/2n3p1/2p4p/P5PP/1P6/2PPPP2/NNRKBQRB w GCgc - 0 9 perft 1 24 perft 2 804 @@ -675,7 +676,7 @@ perft 4 684001 perft 5 18761475 perft 6 617932151 -id 1 +id 75 epd nbkr1qbr/1pp1pppp/pn1p4/8/3P2P1/5R2/PPP1PP1P/NBN1KQBR w H - 2 9 perft 1 30 perft 2 627 @@ -684,7 +685,7 @@ perft 4 423329 perft 5 12815016 perft 6 312798696 -id 1 +id 76 epd nnr1kqbr/pp1pp1p1/2p5/b4p1p/P7/1PNP4/2P1PPPP/N1RBKQBR w HChc - 1 9 perft 1 12 perft 2 421 @@ -693,7 +694,7 @@ perft 4 227044 perft 5 4266410 perft 6 149176979 -id 1 +id 77 epd n1rkqbbr/p1pp1pp1/np2p2p/8/8/N4PP1/PPPPP1BP/N1RKQ1BR w HChc - 0 9 perft 1 27 perft 2 670 @@ -702,7 +703,7 @@ perft 4 494690 perft 5 14708490 perft 6 397268628 -id 1 +id 78 epd nnr1qrbb/p2kpppp/1p1p4/2p5/6P1/PP1P4/2P1PP1P/NNRKQRBB w FC - 0 9 perft 1 27 perft 2 604 @@ -711,7 +712,7 @@ perft 4 409665 perft 5 11993332 perft 6 308518181 -id 1 +id 79 epd bbnnrkrq/ppp1pp2/6p1/3p4/7p/7P/PPPPPPP1/BBNNRRKQ w ge - 0 9 perft 1 20 perft 2 559 @@ -720,7 +721,7 @@ perft 4 355326 perft 5 8427161 perft 6 252274233 -id 1 +id 80 epd bnnbrkr1/ppp2p1p/5q2/3pp1p1/4P3/1N4P1/PPPPRP1P/BN1B1KRQ w Gge - 0 9 perft 1 26 perft 2 1036 @@ -729,7 +730,7 @@ perft 4 1028084 perft 5 28286576 perft 6 1042120495 -id 1 +id 81 epd bn1rkbrq/1pppppp1/p6p/1n6/3P4/6PP/PPPRPP2/BNN1KBRQ w Ggd - 2 9 perft 1 29 perft 2 633 @@ -738,7 +739,7 @@ perft 4 455476 perft 5 14333034 perft 6 361900466 -id 1 +id 82 epd b1nrkrqb/1p1npppp/p2p4/2p5/5P2/4P2P/PPPP1RP1/BNNRK1QB w Dfd - 1 9 perft 1 25 perft 2 475 @@ -747,7 +748,7 @@ perft 4 270909 perft 5 7545536 perft 6 179579818 -id 1 +id 83 epd 1bbnrkrq/ppppppp1/8/7p/1n4P1/1PN5/P1PPPP1P/NBBR1KRQ w Gge - 0 9 perft 1 30 perft 2 803 @@ -756,7 +757,7 @@ perft 4 709716 perft 5 23443854 perft 6 686365049 -id 1 +id 84 epd nnbbrkrq/2pp1pp1/1p5p/pP2p3/7P/N7/P1PPPPP1/N1BBRKRQ w GEge - 0 9 perft 1 18 perft 2 432 @@ -765,7 +766,7 @@ perft 4 242350 perft 5 6131124 perft 6 160393505 -id 1 +id 85 epd nnbrkbrq/1pppp1p1/p7/7p/1P2Pp2/BN6/P1PP1PPP/1N1RKBRQ w GDgd - 0 9 perft 1 27 perft 2 482 @@ -774,7 +775,7 @@ perft 4 282259 perft 5 8084701 perft 6 193484216 -id 1 +id 86 epd n1brkrqb/pppp3p/n3pp2/6p1/3P1P2/N1P5/PP2P1PP/N1BRKRQB w FDfd - 0 9 perft 1 28 perft 2 642 @@ -783,7 +784,7 @@ perft 4 471729 perft 5 14529434 perft 6 384837696 -id 1 +id 87 epd nbnrbk2/p1pppp1p/1p3qr1/6p1/1B1P4/1N6/PPP1PPPP/1BNR1RKQ w d - 2 9 perft 1 30 perft 2 796 @@ -792,7 +793,7 @@ perft 4 687302 perft 5 20120565 perft 6 641832725 -id 1 +id 88 epd nnrbbrkq/1pp2ppp/3p4/p3p3/3P1P2/1P2P3/P1P3PP/NNRBBKRQ w GC - 1 9 perft 1 31 perft 2 827 @@ -801,7 +802,7 @@ perft 4 663082 perft 5 19979594 perft 6 549437308 -id 1 +id 89 epd nnrkbbrq/1pp2p1p/p2pp1p1/2P5/8/8/PP1PPPPP/NNRKBBRQ w Ggc - 0 9 perft 1 24 perft 2 762 @@ -810,7 +811,7 @@ perft 4 624598 perft 5 16838099 perft 6 555230555 -id 1 +id 90 epd nnr1brqb/1ppkp1pp/8/p2p1p2/1P1P4/N1P5/P3PPPP/N1RKBRQB w FC - 1 9 perft 1 23 perft 2 640 @@ -819,7 +820,7 @@ perft 4 444905 perft 5 11343507 perft 6 334123513 -id 1 +id 91 epd nbnrkrbq/2ppp2p/p4p2/1P4p1/4PP2/8/1PPP2PP/NBNRKRBQ w FDfd - 0 9 perft 1 31 perft 2 826 @@ -828,7 +829,7 @@ perft 4 732175 perft 5 23555139 perft 6 686250413 -id 1 +id 92 epd 1nrbkr1q/1pppp1pp/1n6/p4p2/N1b4P/8/PPPPPPPB/N1RBKR1Q w FCfc - 2 9 perft 1 27 perft 2 862 @@ -837,7 +838,7 @@ perft 4 755171 perft 5 22027695 perft 6 696353497 -id 1 +id 93 epd nnrkrbbq/pppp2pp/8/4pp2/4P3/P7/1PPPBPPP/NNKRR1BQ w c - 0 9 perft 1 25 perft 2 792 @@ -846,7 +847,7 @@ perft 4 636041 perft 5 16473376 perft 6 532214177 -id 1 +id 94 epd n1rk1qbb/pppprpp1/2n4p/4p3/2PP3P/8/PP2PPP1/NNRKRQBB w ECc - 1 9 perft 1 25 perft 2 622 @@ -855,7 +856,7 @@ perft 4 425247 perft 5 11420973 perft 6 321855685 -id 1 +id 95 epd bbq1rnkr/pnp1pp1p/1p1p4/6p1/2P5/2Q1P2P/PP1P1PP1/BB1NRNKR w HEhe - 2 9 perft 1 36 perft 2 870 @@ -864,7 +865,7 @@ perft 4 811047 perft 5 28127620 perft 6 799738334 -id 1 +id 96 epd bq1brnkr/1p1ppp1p/1np5/p5p1/8/1N5P/PPPPPPP1/BQ1BRNKR w HEhe - 0 9 perft 1 22 perft 2 588 @@ -873,7 +874,7 @@ perft 4 380068 perft 5 9359618 perft 6 273795898 -id 1 +id 97 epd bq1rn1kr/1pppppbp/Nn4p1/8/8/P7/1PPPPPPP/BQ1RNBKR w HDhd - 1 9 perft 1 24 perft 2 711 @@ -882,7 +883,7 @@ perft 4 542570 perft 5 14692779 perft 6 445827351 -id 1 +id 98 epd bqnr1kr1/pppppp1p/6p1/5n2/4B3/3N2PP/PbPPPP2/BQNR1KR1 w GDgd - 2 9 perft 1 31 perft 2 1132 @@ -891,7 +892,7 @@ perft 4 1261476 perft 5 43256823 perft 6 1456721391 -id 1 +id 99 epd qbb1rnkr/ppp3pp/4n3/3ppp2/1P3PP1/8/P1PPPN1P/QBB1RNKR w HEhe - 0 9 perft 1 28 perft 2 696 @@ -900,7 +901,7 @@ perft 4 541886 perft 5 16492398 perft 6 456983120 -id 1 +id 100 epd qnbbr1kr/pp1ppp1p/4n3/6p1/2p3P1/2PP1P2/PP2P2P/QNBBRNKR w HEhe - 0 9 perft 1 25 perft 2 655 @@ -909,7 +910,7 @@ perft 4 450189 perft 5 11767038 perft 6 335414976 -id 1 +id 101 epd 1nbrnbkr/p1ppp1pp/1p6/5p2/4q1PP/3P4/PPP1PP2/QNBRNBKR w HDhd - 1 9 perft 1 30 perft 2 1162 @@ -918,7 +919,7 @@ perft 4 1217278 perft 5 36048727 perft 6 1290346802 -id 1 +id 102 epd q1brnkrb/p1pppppp/n7/1p6/P7/3P1P2/QPP1P1PP/1NBRNKRB w GDgd - 0 9 perft 1 32 perft 2 827 @@ -927,7 +928,7 @@ perft 4 718243 perft 5 23143989 perft 6 673147648 -id 1 +id 103 epd qbnrb1kr/ppp1pp1p/3p4/2n3p1/1P6/6N1/P1PPPPPP/QBNRB1KR w HDhd - 2 9 perft 1 29 perft 2 751 @@ -936,7 +937,7 @@ perft 4 610397 perft 5 19555214 perft 6 530475036 -id 1 +id 104 epd q1rbbnkr/pppp1p2/2n3pp/2P1p3/3P4/8/PP1NPPPP/Q1RBBNKR w HChc - 2 9 perft 1 29 perft 2 806 @@ -945,7 +946,7 @@ perft 4 687251 perft 5 21694330 perft 6 619907316 -id 1 +id 105 epd q1r1bbkr/pnpp1ppp/2n1p3/1p6/2P2P2/2N1N3/PP1PP1PP/Q1R1BBKR w HChc - 2 9 perft 1 32 perft 2 1017 @@ -954,7 +955,7 @@ perft 4 986028 perft 5 31204371 perft 6 958455898 -id 1 +id 106 epd 2rnbkrb/pqppppp1/1pn5/7p/2P5/P1R5/QP1PPPPP/1N1NBKRB w Ggc - 4 9 perft 1 26 perft 2 625 @@ -963,7 +964,7 @@ perft 4 434635 perft 5 11856964 perft 6 336672890 -id 1 +id 107 epd qbnr1kbr/p2ppppp/2p5/1p6/4n2P/P4N2/1PPP1PP1/QBNR1KBR w HDhd - 0 9 perft 1 27 perft 2 885 @@ -972,7 +973,7 @@ perft 4 767273 perft 5 21855658 perft 6 706272554 -id 1 +id 108 epd qnrbnk1r/pp1pp2p/5p2/2pbP1p1/3P4/1P6/P1P2PPP/QNRBNKBR w HChc - 0 9 perft 1 26 perft 2 954 @@ -981,7 +982,7 @@ perft 4 892456 perft 5 24415089 perft 6 866744329 -id 1 +id 109 epd qnrnk1br/p1p2ppp/8/1pbpp3/8/PP2N3/1QPPPPPP/1NR1KBBR w HChc - 0 9 perft 1 26 perft 2 783 @@ -990,7 +991,7 @@ perft 4 634267 perft 5 17477825 perft 6 539674275 -id 1 +id 110 epd qnrnkrbb/Bpppp2p/6p1/5p2/5P2/3PP3/PPP3PP/QNRNKR1B w FCfc - 1 9 perft 1 28 perft 2 908 @@ -999,7 +1000,7 @@ perft 4 861240 perft 5 25251641 perft 6 869525254 -id 1 +id 111 epd bbnqrn1r/ppppp2k/5p2/6pp/7P/1QP5/PP1PPPP1/B1N1RNKR w HE - 0 9 perft 1 33 perft 2 643 @@ -1008,7 +1009,7 @@ perft 4 487109 perft 5 16693640 perft 6 410115900 -id 1 +id 112 epd b1qbrnkr/ppp1pp2/2np4/6pp/4P3/2N4P/PPPP1PP1/BQ1BRNKR w HEhe - 0 9 perft 1 28 perft 2 837 @@ -1017,7 +1018,7 @@ perft 4 745617 perft 5 22197063 perft 6 696399065 -id 1 +id 113 epd bnqr1bkr/pp1ppppp/2p5/4N3/5P2/P7/1PPPPnPP/BNQR1BKR w HDhd - 3 9 perft 1 25 perft 2 579 @@ -1026,7 +1027,7 @@ perft 4 341444 perft 5 8601011 perft 6 225530258 -id 1 +id 114 epd b1qr1krb/pp1ppppp/n2n4/8/2p5/2P3P1/PP1PPP1P/BNQRNKRB w GDgd - 0 9 perft 1 28 perft 2 707 @@ -1035,7 +1036,7 @@ perft 4 549506 perft 5 15583376 perft 6 468399900 -id 1 +id 115 epd nbbqr1kr/1pppp1pp/8/p1n2p2/4P3/PN6/1PPPQPPP/1BB1RNKR w HEhe - 0 9 perft 1 30 perft 2 745 @@ -1044,7 +1045,7 @@ perft 4 597858 perft 5 19478789 perft 6 515473678 -id 1 +id 116 epd nqbbrn1r/p1pppp1k/1p4p1/7p/4P3/1R3B2/PPPP1PPP/NQB2NKR w H - 0 9 perft 1 24 perft 2 504 @@ -1053,7 +1054,7 @@ perft 4 317355 perft 5 9002073 perft 6 228726497 -id 1 +id 117 epd nqbr1bkr/p1p1ppp1/1p1n4/3pN2p/1P6/8/P1PPPPPP/NQBR1BKR w HDhd - 0 9 perft 1 29 perft 2 898 @@ -1062,7 +1063,7 @@ perft 4 809605 perft 5 24703467 perft 6 757166494 -id 1 +id 118 epd nqbrn1rb/pppp1kp1/5p1p/4p3/P4B2/3P2P1/1PP1PP1P/NQ1RNKRB w GD - 0 9 perft 1 34 perft 2 671 @@ -1071,7 +1072,7 @@ perft 4 473110 perft 5 15556806 perft 6 353235120 -id 1 +id 119 epd nb1r1nkr/ppp1ppp1/2bp4/7p/3P2qP/P6R/1PP1PPP1/NBQRBNK1 w Dhd - 1 9 perft 1 38 perft 2 1691 @@ -1080,7 +1081,7 @@ perft 4 2526992 perft 5 88557078 perft 6 3589649998 -id 1 +id 120 epd n1rbbnkr/1p1pp1pp/p7/2p1qp2/1B3P2/3P4/PPP1P1PP/NQRB1NKR w HChc - 0 9 perft 1 24 perft 2 913 @@ -1089,7 +1090,7 @@ perft 4 807544 perft 5 19866918 perft 6 737239330 -id 1 +id 121 epd nqrnbbkr/p2p1p1p/1pp5/1B2p1p1/1P3P2/4P3/P1PP2PP/NQRNB1KR w HChc - 0 9 perft 1 33 perft 2 913 @@ -1098,7 +1099,7 @@ perft 4 843874 perft 5 28053260 perft 6 804687975 -id 1 +id 122 epd nqr1bkrb/ppp1pp2/2np2p1/P6p/8/2P4P/1P1PPPP1/NQRNBKRB w GCgc - 0 9 perft 1 24 perft 2 623 @@ -1107,7 +1108,7 @@ perft 4 442531 perft 5 12681936 perft 6 351623879 -id 1 +id 123 epd nb1rnkbr/pqppppp1/1p5p/8/1PP4P/8/P2PPPP1/NBQRNKBR w HDhd - 1 9 perft 1 31 perft 2 798 @@ -1116,7 +1117,7 @@ perft 4 694386 perft 5 22616076 perft 6 666227466 -id 1 +id 124 epd nqrbnkbr/2p1p1pp/3p4/pp3p2/6PP/3P1N2/PPP1PP2/NQRB1KBR w HChc - 0 9 perft 1 24 perft 2 590 @@ -1125,7 +1126,7 @@ perft 4 383690 perft 5 9698432 perft 6 274064911 -id 1 +id 125 epd nqrnkbbr/pp1p1p1p/4p1p1/1p6/8/5P1P/P1PPP1P1/NQRNKBBR w HChc - 0 9 perft 1 30 perft 2 1032 @@ -1134,7 +1135,7 @@ perft 4 1098116 perft 5 34914919 perft 6 1233362066 -id 1 +id 126 epd nqrnkrbb/p2ppppp/1p6/2p5/2P3P1/5P2/PP1PPN1P/NQR1KRBB w FCfc - 1 9 perft 1 30 perft 2 775 @@ -1143,7 +1144,7 @@ perft 4 668000 perft 5 21141738 perft 6 621142773 -id 1 +id 127 epd bbnrqrk1/pp2pppp/4n3/2pp4/P7/1N5P/BPPPPPP1/B2RQNKR w HD - 2 9 perft 1 23 perft 2 708 @@ -1152,7 +1153,7 @@ perft 4 554089 perft 5 14343443 perft 6 481405144 -id 1 +id 128 epd bnr1qnkr/p1pp1p1p/1p4p1/4p1b1/2P1P3/1P6/PB1P1PPP/1NRBQNKR w HChc - 1 9 perft 1 30 perft 2 931 @@ -1161,7 +1162,7 @@ perft 4 921746 perft 5 30026687 perft 6 968109774 -id 1 +id 129 epd b1rqnbkr/ppp1ppp1/3p3p/2n5/P3P3/2NP4/1PP2PPP/B1RQNBKR w HChc - 0 9 perft 1 24 perft 2 596 @@ -1170,7 +1171,7 @@ perft 4 396123 perft 5 11099382 perft 6 294180723 -id 1 +id 130 epd bnrqnr1b/pp1pkppp/2p1p3/P7/2P5/7P/1P1PPPP1/BNRQNKRB w GC - 0 9 perft 1 24 perft 2 572 @@ -1179,7 +1180,7 @@ perft 4 390903 perft 5 11208688 perft 6 302955778 -id 1 +id 131 epd n1brq1kr/bppppppp/p7/8/4P1Pn/8/PPPP1P2/NBBRQNKR w HDhd - 0 9 perft 1 20 perft 2 570 @@ -1188,7 +1189,7 @@ perft 4 371247 perft 5 9919113 perft 6 284592289 -id 1 +id 132 epd 1rbbqnkr/ppn1ppp1/3p3p/2p5/3P4/1N4P1/PPPBPP1P/1R1BQNKR w HBhb - 0 9 perft 1 29 perft 2 1009 @@ -1197,7 +1198,7 @@ perft 4 1040816 perft 5 31059587 perft 6 1111986835 -id 1 +id 133 epd nrbq2kr/ppppppb1/5n1p/5Pp1/8/P5P1/1PPPP2P/NRBQNBKR w HBhb - 1 9 perft 1 20 perft 2 520 @@ -1206,7 +1207,7 @@ perft 4 316332 perft 5 7809837 perft 6 216997152 -id 1 +id 134 epd nrb1nkrb/pp3ppp/1qBpp3/2p5/8/P5P1/1PPPPP1P/NRBQNKR1 w GBgb - 2 9 perft 1 32 perft 2 850 @@ -1215,7 +1216,7 @@ perft 4 734088 perft 5 21981567 perft 6 664886187 -id 1 +id 135 epd 1br1bnkr/ppqppp1p/1np3p1/8/1PP4P/4N3/P2PPPP1/NBRQB1KR w HChc - 1 9 perft 1 32 perft 2 798 @@ -1224,7 +1225,7 @@ perft 4 691488 perft 5 22076141 perft 6 670296871 -id 1 +id 136 epd nrqbb1kr/1p1pp1pp/2p3n1/p4p2/3PP3/P5N1/1PP2PPP/NRQBB1KR w HBhb - 0 9 perft 1 32 perft 2 791 @@ -1233,7 +1234,7 @@ perft 4 684890 perft 5 23239122 perft 6 634260266 -id 1 +id 137 epd nrqn1bkr/ppppp1pp/4b3/8/4P1p1/5P2/PPPP3P/NRQNBBKR w HBhb - 0 9 perft 1 29 perft 2 687 @@ -1242,7 +1243,7 @@ perft 4 506088 perft 5 15236287 perft 6 398759980 -id 1 +id 138 epd nrqnbrkb/pppp1p2/4p2p/3B2p1/8/1P4P1/PQPPPP1P/NR1NBKR1 w GB - 0 9 perft 1 37 perft 2 764 @@ -1251,7 +1252,7 @@ perft 4 610950 perft 5 21284835 perft 6 514864869 -id 1 +id 139 epd nbrq1kbr/Bp3ppp/2pnp3/3p4/5P2/2P4P/PP1PP1P1/NBRQNK1R w HChc - 0 9 perft 1 40 perft 2 1271 @@ -1260,7 +1261,7 @@ perft 4 1547741 perft 5 56588117 perft 6 1850696281 -id 1 +id 140 epd nrqbnkbr/1p2ppp1/p1p4p/3p4/1P6/8/PQPPPPPP/1RNBNKBR w HBhb - 0 9 perft 1 28 perft 2 757 @@ -1269,7 +1270,7 @@ perft 4 668025 perft 5 21427496 perft 6 650939962 -id 1 +id 141 epd nrqn1bbr/2ppkppp/4p3/pB6/8/2P1P3/PP1P1PPP/NRQNK1BR w HB - 1 9 perft 1 27 perft 2 642 @@ -1278,7 +1279,7 @@ perft 4 442653 perft 5 11872805 perft 6 327545120 -id 1 +id 142 epd nrqnkrb1/p1ppp2p/1p4p1/4bp2/4PP1P/4N3/PPPP2P1/NRQ1KRBB w FBfb - 1 9 perft 1 27 perft 2 958 @@ -1287,7 +1288,7 @@ perft 4 960350 perft 5 28520172 perft 6 995356563 -id 1 +id 143 epd 1bnrnqkr/pbpp2pp/8/1p2pp2/P6P/3P1N2/1PP1PPP1/BBNR1QKR w HDhd - 0 9 perft 1 27 perft 2 859 @@ -1296,7 +1297,7 @@ perft 4 773232 perft 5 21581178 perft 6 732696327 -id 1 +id 144 epd b1rbnqkr/1pp1ppp1/2n4p/p2p4/5P2/1PBP4/P1P1P1PP/1NRBNQKR w HChc - 0 9 perft 1 26 perft 2 545 @@ -1305,7 +1306,7 @@ perft 4 336470 perft 5 9537260 perft 6 233549184 -id 1 +id 145 epd 1nrnqbkr/p1pppppp/1p6/8/2b2P2/P1N5/1PP1P1PP/BNR1QBKR w HChc - 2 9 perft 1 24 perft 2 668 @@ -1314,7 +1315,7 @@ perft 4 494866 perft 5 14216070 perft 6 406225409 -id 1 +id 146 epd 1nrnqkrb/2ppp1pp/p7/1p3p2/5P2/N5K1/PPPPP2P/B1RNQ1RB w gc - 0 9 perft 1 33 perft 2 725 @@ -1323,7 +1324,7 @@ perft 4 559823 perft 5 18547476 perft 6 471443091 -id 1 +id 147 epd nbbr1qkr/p1pppppp/8/1p1n4/3P4/1N3PP1/PPP1P2P/1BBRNQKR w HDhd - 1 9 perft 1 28 perft 2 698 @@ -1332,7 +1333,7 @@ perft 4 539625 perft 5 16555068 perft 6 458045505 -id 1 +id 148 epd 1rbbnqkr/1pnppp1p/p5p1/2p5/2P4P/5P2/PP1PP1PR/NRBBNQK1 w Bhb - 1 9 perft 1 24 perft 2 554 @@ -1341,7 +1342,7 @@ perft 4 362516 perft 5 9863080 perft 6 269284081 -id 1 +id 149 epd nrb1qbkr/2pppppp/2n5/p7/2p5/4P3/PPNP1PPP/1RBNQBKR w HBhb - 0 9 perft 1 23 perft 2 618 @@ -1350,7 +1351,7 @@ perft 4 443718 perft 5 12044358 perft 6 360311412 -id 1 +id 150 epd nrb1qkrb/2ppppp1/p3n3/1p1B3p/2P5/6P1/PP1PPPRP/NRBNQK2 w Bgb - 2 9 perft 1 27 perft 2 593 @@ -1359,7 +1360,7 @@ perft 4 401967 perft 5 11806808 perft 6 303338935 -id 1 +id 151 epd nbrn1qkr/ppp1pp2/3p2p1/3Q3P/b7/8/PPPPPP1P/NBRNB1KR w HChc - 2 9 perft 1 39 perft 2 1056 @@ -1368,7 +1369,7 @@ perft 4 1133446 perft 5 42201531 perft 6 1239888683 -id 1 +id 152 epd nr1bbqkr/pp1pp2p/1n3pp1/2p5/8/1P4P1/P1PPPPQP/NRNBBK1R w hb - 0 9 perft 1 25 perft 2 585 @@ -1377,7 +1378,7 @@ perft 4 406544 perft 5 11582539 perft 6 320997679 -id 1 +id 153 epd nr2bbkr/ppp1pppp/1n1p4/8/6PP/1NP4q/PP1PPP2/1RNQBBKR w HBhb - 1 9 perft 1 22 perft 2 742 @@ -1386,7 +1387,7 @@ perft 4 545231 perft 5 13287051 perft 6 457010195 -id 1 +id 154 epd 1rnqbkrb/ppp1p1p1/1n3p2/3p3p/P6P/4P3/1PPP1PP1/NRNQBRKB w gb - 0 9 perft 1 22 perft 2 574 @@ -1395,7 +1396,7 @@ perft 4 379648 perft 5 9968830 perft 6 281344367 -id 1 +id 155 epd nb1rqkbr/1pppp1pp/4n3/p4p2/6PP/5P2/PPPPPN2/NBR1QKBR w HCh - 0 9 perft 1 25 perft 2 621 @@ -1404,7 +1405,7 @@ perft 4 462600 perft 5 13378840 perft 6 396575613 -id 1 +id 156 epd nrnbqkbr/2pp2pp/4pp2/pp6/8/1P3P2/P1PPPBPP/NRNBQ1KR w hb - 0 9 perft 1 25 perft 2 656 @@ -1413,7 +1414,7 @@ perft 4 466493 perft 5 12525939 perft 6 358763789 -id 1 +id 157 epd nrnqkbbr/ppppp1p1/7p/5p2/8/P4PP1/NPPPP2P/NR1QKBBR w HBhb - 0 9 perft 1 28 perft 2 723 @@ -1422,7 +1423,7 @@ perft 4 547522 perft 5 15952533 perft 6 439046803 -id 1 +id 158 epd 1rnqkr1b/ppppp2p/1n3pp1/8/2P3P1/Pb1N4/1P1PPP1P/NR1QKRBB w FBfb - 0 9 perft 1 26 perft 2 713 @@ -1431,7 +1432,7 @@ perft 4 548875 perft 5 15865528 perft 6 454532806 -id 1 +id 159 epd bbnrnkqr/1pppp1pp/5p2/p7/7P/1P6/PBPPPPPR/1BNRNKQ1 w D - 2 9 perft 1 26 perft 2 649 @@ -1440,7 +1441,7 @@ perft 4 502279 perft 5 14375839 perft 6 435585252 -id 1 +id 160 epd bnrbk1qr/1ppp1ppp/p2np3/8/P7/2N2P2/1PPPP1PP/B1RBNKQR w HC - 0 9 perft 1 26 perft 2 621 @@ -1449,7 +1450,7 @@ perft 4 451452 perft 5 13514201 perft 6 364421088 -id 1 +id 161 epd br1nkbqr/ppppppp1/8/n6p/8/N1P2PP1/PP1PP2P/B1RNKBQR w HCh - 1 9 perft 1 29 perft 2 664 @@ -1458,7 +1459,7 @@ perft 4 512316 perft 5 16125924 perft 6 442508159 -id 1 +id 162 epd bnr1kqrb/pp1pppp1/2n5/2p5/1P4Pp/4N3/P1PPPP1P/BNKR1QRB w gc - 0 9 perft 1 36 perft 2 888 @@ -1467,7 +1468,7 @@ perft 4 789863 perft 5 27792175 perft 6 719015345 -id 1 +id 163 epd 1bbrnkqr/pp1p1ppp/2p1p3/1n6/5P2/3Q4/PPPPP1PP/NBBRNK1R w HDhd - 2 9 perft 1 36 perft 2 891 @@ -1476,7 +1477,7 @@ perft 4 781792 perft 5 26998966 perft 6 702903862 -id 1 +id 164 epd nrbbnk1r/pp2pppq/8/2pp3p/3P2P1/1N6/PPP1PP1P/1RBBNKQR w HBhb - 0 9 perft 1 29 perft 2 1036 @@ -1485,7 +1486,7 @@ perft 4 1139166 perft 5 35627310 perft 6 1310683359 -id 1 +id 165 epd nr1nkbqr/ppp3pp/5p2/3pp3/6b1/3PP3/PPP2PPP/NRBNKBQR w hb - 0 9 perft 1 18 perft 2 664 @@ -1494,7 +1495,7 @@ perft 4 483892 perft 5 10658989 perft 6 386307449 -id 1 +id 166 epd nrbnk1rb/ppp1pq1p/3p4/5pp1/2P1P3/1N6/PP1PKPPP/1RBN1QRB w gb - 2 9 perft 1 25 perft 2 966 @@ -1503,7 +1504,7 @@ perft 4 920345 perft 5 23957242 perft 6 913710194 -id 1 +id 167 epd 1brnbkqr/pppppp2/6p1/7p/1Pn5/P1NP4/2P1PPPP/NBR1BKQR w HChc - 0 9 perft 1 22 perft 2 627 @@ -1512,7 +1513,7 @@ perft 4 395829 perft 5 9627826 perft 6 285900573 -id 1 +id 168 epd nrnbbk1r/p1pppppq/8/7p/1p6/P5PP/1PPPPPQ1/NRNBBK1R w HBhb - 2 9 perft 1 29 perft 2 888 @@ -1521,7 +1522,7 @@ perft 4 874270 perft 5 27229468 perft 6 930799376 -id 1 +id 169 epd n1nkb1qr/prppppbp/6p1/1p6/2P2P2/P7/1P1PP1PP/NRNKBBQR w HBh - 1 9 perft 1 29 perft 2 804 @@ -1530,7 +1531,7 @@ perft 4 688520 perft 5 21952444 perft 6 623156747 -id 1 +id 170 epd nr2bqrb/ppkpp1pp/1np5/5p1P/5P2/2P5/PP1PP1P1/NRNKBQRB w GB - 0 9 perft 1 22 perft 2 530 @@ -1539,7 +1540,7 @@ perft 4 347657 perft 5 9244693 perft 6 264088392 -id 1 +id 171 epd nbr1kqbr/p3pppp/2ppn3/1p4P1/4P3/1P6/P1PP1P1P/NBRNKQBR w HChc - 1 9 perft 1 23 perft 2 555 @@ -1548,7 +1549,7 @@ perft 4 350917 perft 5 9692630 perft 6 247479180 -id 1 +id 172 epd nr1bkqbr/1p1pp1pp/pnp2p2/8/6P1/P1PP4/1P2PP1P/NRNBKQBR w HBhb - 0 9 perft 1 22 perft 2 565 @@ -1557,7 +1558,7 @@ perft 4 365663 perft 5 9305533 perft 6 268612479 -id 1 +id 173 epd nr1kqbbr/np2pppp/p1p5/1B1p1P2/8/4P3/PPPP2PP/NRNKQ1BR w HBhb - 0 9 perft 1 32 perft 2 730 @@ -1566,7 +1567,7 @@ perft 4 556995 perft 5 18103280 perft 6 454569900 -id 1 +id 174 epd nrnk1rbb/p1p2ppp/3pq3/Qp2p3/1P1P4/8/P1P1PPPP/NRN1KRBB w fb - 2 9 perft 1 28 perft 2 873 @@ -1575,7 +1576,7 @@ perft 4 791823 perft 5 23868737 perft 6 747991356 -id 1 +id 175 epd bbnrnkrq/pp1ppp1p/6p1/2p5/6P1/P5RP/1PPPPP2/BBNRNK1Q w Dgd - 3 9 perft 1 37 perft 2 1260 @@ -1584,7 +1585,7 @@ perft 4 1542086 perft 5 54843403 perft 6 1898432768 -id 1 +id 176 epd bnrb1rkq/ppnpppp1/3Q4/2p4p/7P/N7/PPPPPPP1/B1RBNKR1 w GC - 2 9 perft 1 38 perft 2 878 @@ -1593,7 +1594,7 @@ perft 4 800440 perft 5 28784300 perft 6 784569826 -id 1 +id 177 epd bnrnkbrq/p1ppppp1/1p5p/8/P2PP3/5P2/1PP3PP/BNRNKBRQ w GCgc - 1 9 perft 1 26 perft 2 617 @@ -1602,7 +1603,7 @@ perft 4 419099 perft 5 11965544 perft 6 311309576 -id 1 +id 178 epd bnrnkrqb/pp2p2p/2pp1pp1/8/P7/2PP1P2/1P2P1PP/BNRNKRQB w FCfc - 0 9 perft 1 26 perft 2 721 @@ -1611,7 +1612,7 @@ perft 4 560824 perft 5 15966934 perft 6 467132503 -id 1 +id 179 epd nbbrnkr1/1pppp1p1/p6q/P4p1p/8/5P2/1PPPP1PP/NBBRNRKQ w gd - 2 9 perft 1 18 perft 2 556 @@ -1620,7 +1621,7 @@ perft 4 316634 perft 5 6629293 perft 6 202528241 -id 1 +id 180 epd nrb1nkrq/2pp1ppp/p4b2/1p2p3/P4B2/3P4/1PP1PPPP/NR1BNRKQ w gb - 0 9 perft 1 24 perft 2 562 @@ -1629,7 +1630,7 @@ perft 4 355433 perft 5 9227883 perft 6 247634489 -id 1 +id 181 epd nrbnkbrq/p3p1pp/1p6/2pp1P2/8/3PP3/PPP2P1P/NRBNKBRQ w GBgb - 0 9 perft 1 31 perft 2 746 @@ -1638,7 +1639,7 @@ perft 4 608523 perft 5 21019301 perft 6 542954168 -id 1 +id 182 epd nrbnkrqb/pppp1p1p/4p1p1/8/7P/2P1P3/PPNP1PP1/1RBNKRQB w FBfb - 0 9 perft 1 20 perft 2 459 @@ -1647,7 +1648,7 @@ perft 4 242762 perft 5 5760165 perft 6 146614723 -id 1 +id 183 epd nbrn1krq/ppp1p2p/6b1/3p1pp1/8/4N1PP/PPPPPP2/NBR1BRKQ w gc - 1 9 perft 1 27 perft 2 835 @@ -1656,7 +1657,7 @@ perft 4 766397 perft 5 22667987 perft 6 760795567 -id 1 +id 184 epd nrnbbkrq/p1pp2pp/5p2/1p6/2P1pP1B/1P6/P2PP1PP/NRNB1KRQ w GBgb - 0 9 perft 1 24 perft 2 646 @@ -1665,7 +1666,7 @@ perft 4 444472 perft 5 11489727 perft 6 324948755 -id 1 +id 185 epd nrn1bbrq/1ppkppp1/p2p3p/8/1P3N2/4P3/P1PP1PPP/NR1KBBRQ w GB - 2 9 perft 1 32 perft 2 591 @@ -1674,7 +1675,7 @@ perft 4 381683 perft 5 12069159 perft 6 269922838 -id 1 +id 186 epd n1krbrqb/1ppppppp/p7/8/4n3/P4P1P/1PPPPQP1/NRNKBR1B w FB - 2 9 perft 1 26 perft 2 639 @@ -1683,7 +1684,7 @@ perft 4 417190 perft 5 12167153 perft 6 312633873 -id 1 +id 187 epd n1rnkrbq/1p1ppp1p/8/p1p1b1p1/3PQ1P1/4N3/PPP1PP1P/NBR1KRB1 w FCfc - 0 9 perft 1 35 perft 2 1027 @@ -1692,7 +1693,7 @@ perft 4 1040417 perft 5 35738410 perft 6 1060661628 -id 1 +id 188 epd nrnbkrbq/2pp1pp1/pp6/4p2p/P7/5PPP/1PPPP3/NRNBKRBQ w FBfb - 0 9 perft 1 26 perft 2 628 @@ -1701,7 +1702,7 @@ perft 4 436075 perft 5 11920087 perft 6 331498921 -id 1 +id 189 epd 1rnkrbbq/pp1p2pp/1n3p2/1Bp1p3/1P6/1N2P3/P1PP1PPP/1RNKR1BQ w EBeb - 0 9 perft 1 33 perft 2 992 @@ -1710,7 +1711,7 @@ perft 4 983481 perft 5 31703749 perft 6 980306735 -id 1 +id 190 epd nr1krqbb/p1ppppp1/8/1p5p/1Pn5/5P2/P1PPP1PP/NRNKRQBB w EBeb - 0 9 perft 1 24 perft 2 670 @@ -1719,7 +1720,7 @@ perft 4 445492 perft 5 11371067 perft 6 325556465 -id 1 +id 191 epd bbq1rkr1/1ppppppp/p1n2n2/8/2P2P2/1P6/PQ1PP1PP/BB1NRKNR w HEe - 3 9 perft 1 32 perft 2 794 @@ -1728,7 +1729,7 @@ perft 4 689334 perft 5 24085223 perft 6 645633370 -id 1 +id 192 epd b1nbrknr/1qppp1pp/p4p2/1p6/6P1/P2NP3/1PPP1P1P/BQ1BRKNR w HEhe - 1 9 perft 1 25 perft 2 663 @@ -1737,7 +1738,7 @@ perft 4 482994 perft 5 13157826 perft 6 389603029 -id 1 +id 193 epd bqnrk1nr/pp2ppbp/6p1/2pp4/2P5/5P2/PPQPP1PP/B1NRKBNR w HDhd - 0 9 perft 1 26 perft 2 850 @@ -1746,7 +1747,7 @@ perft 4 759768 perft 5 21341087 perft 6 719712622 -id 1 +id 194 epd bqnrknrb/1ppp1p1p/p7/6p1/1P2p3/P1PN4/3PPPPP/BQ1RKNRB w GDgd - 0 9 perft 1 25 perft 2 721 @@ -1755,7 +1756,7 @@ perft 4 581913 perft 5 16391601 perft 6 511725087 -id 1 +id 195 epd q1b1rknr/pp1pppp1/4n2p/2p1b3/1PP5/4P3/PQ1P1PPP/1BBNRKNR w HEhe - 1 9 perft 1 32 perft 2 975 @@ -1764,7 +1765,7 @@ perft 4 955493 perft 5 32649943 perft 6 962536105 -id 1 +id 196 epd qnbbrknr/1p1ppppp/8/p1p5/5P2/PP1P4/2P1P1PP/QNBBRKNR w HEhe - 0 9 perft 1 27 perft 2 573 @@ -1773,7 +1774,7 @@ perft 4 391656 perft 5 11562434 perft 6 301166330 -id 1 +id 197 epd q1brkb1r/p1pppppp/np3B2/8/6n1/1P5N/P1PPPPPP/QN1RKB1R w HDhd - 0 9 perft 1 32 perft 2 984 @@ -1782,7 +1783,7 @@ perft 4 1007217 perft 5 32597704 perft 6 1075429389 -id 1 +id 198 epd qn1rk1rb/p1pppppp/1p2n3/8/2b5/4NPP1/PPPPP1RP/QNBRK2B w Dgd - 4 9 perft 1 22 perft 2 802 @@ -1791,7 +1792,7 @@ perft 4 697722 perft 5 17761431 perft 6 650603534 -id 1 +id 199 epd qbnrbknr/ppp2p1p/8/3pp1p1/1PP1B3/5N2/P2PPPPP/Q1NRBK1R w HDhd - 0 9 perft 1 34 perft 2 943 @@ -1800,7 +1801,7 @@ perft 4 930619 perft 5 32523099 perft 6 955802240 -id 1 +id 200 epd qnrbb1nr/pp1p1ppp/2p2k2/4p3/4P3/5PPP/PPPP4/QNRBBKNR w HC - 0 9 perft 1 20 perft 2 460 @@ -1809,7 +1810,7 @@ perft 4 241640 perft 5 5846781 perft 6 140714047 -id 1 +id 201 epd qnr1bbnr/ppk1p1pp/3p4/2p2p2/8/2P5/PP1PPPPP/QNKRBBNR w - - 1 9 perft 1 19 perft 2 572 @@ -1818,7 +1819,7 @@ perft 4 357340 perft 5 7994547 perft 6 243724815 -id 1 +id 202 epd qnrkbnrb/1p1p1ppp/2p5/4p3/p7/N1BP4/PPP1PPPP/Q1R1KNRB w gc - 0 9 perft 1 27 perft 2 579 @@ -1827,7 +1828,7 @@ perft 4 375168 perft 5 10845146 perft 6 268229097 -id 1 +id 203 epd qbnrkn1r/1pppp1p1/p3bp2/2BN3p/8/5P2/PPPPP1PP/QBNRK2R w HDhd - 0 9 perft 1 40 perft 2 1027 @@ -1836,7 +1837,7 @@ perft 4 1059229 perft 5 38511307 perft 6 1104094381 -id 1 +id 204 epd qnrbknbr/1pp2ppp/4p3/p6N/2p5/8/PPPPPPPP/Q1RBK1BR w HChc - 0 9 perft 1 22 perft 2 510 @@ -1845,7 +1846,7 @@ perft 4 300180 perft 5 7403327 perft 6 200581103 -id 1 +id 205 epd 1qkrnbbr/p1pppppp/2n5/1p6/8/5NP1/PPPPPP1P/QNRK1BBR w HC - 4 9 perft 1 24 perft 2 549 @@ -1854,7 +1855,7 @@ perft 4 352037 perft 5 9396521 perft 6 255676649 -id 1 +id 206 epd q1rknr1b/1ppppppb/2n5/p2B3p/8/1PN3P1/P1PPPP1P/Q1RKNRB1 w FCfc - 3 9 perft 1 31 perft 2 924 @@ -1863,7 +1864,7 @@ perft 4 861944 perft 5 27463479 perft 6 847726572 -id 1 +id 207 epd bbnqrk1r/pp1pppp1/2p4p/8/6n1/1N1P1P2/PPP1P1PP/BBQ1RKNR w HEhe - 4 9 perft 1 24 perft 2 804 @@ -1872,7 +1873,7 @@ perft 4 666341 perft 5 18024195 perft 6 595947631 -id 1 +id 208 epd bn1brknr/ppp1p1pp/5p2/3p4/6qQ/3P3P/PPP1PPP1/BN1BRKNR w HEhe - 4 9 perft 1 25 perft 2 854 @@ -1881,7 +1882,7 @@ perft 4 704173 perft 5 20290974 perft 6 600195008 -id 1 +id 209 epd 1nqrkbnr/2pp1ppp/pp2p3/3b4/2P5/N7/PP1PPPPP/B1QRKBNR w HDhd - 0 9 perft 1 22 perft 2 651 @@ -1890,7 +1891,7 @@ perft 4 479152 perft 5 13133439 perft 6 390886040 -id 1 +id 210 epd bnqrk1rb/1pp1pppp/p2p4/4n3/2PPP3/8/PP3PPP/BNQRKNRB w GDgd - 1 9 perft 1 30 perft 2 950 @@ -1899,7 +1900,7 @@ perft 4 889687 perft 5 27610213 perft 6 880739164 -id 1 +id 211 epd nbb1rknr/1ppq1ppp/3p4/p3p3/4P3/1N2R3/PPPP1PPP/1BBQ1KNR w Hhe - 2 9 perft 1 33 perft 2 988 @@ -1908,7 +1909,7 @@ perft 4 967575 perft 5 30894863 perft 6 985384035 -id 1 +id 212 epd nqbbrknr/2ppp2p/pp4p1/5p2/7P/3P1P2/PPPBP1P1/NQ1BRKNR w HEhe - 0 9 perft 1 27 perft 2 492 @@ -1917,7 +1918,7 @@ perft 4 276569 perft 5 7583292 perft 6 175376176 -id 1 +id 213 epd 1qbrkb1r/pppppppp/8/3n4/4P1n1/PN6/1PPP1P1P/1QBRKBNR w HDhd - 3 9 perft 1 28 perft 2 800 @@ -1926,7 +1927,7 @@ perft 4 630374 perft 5 17313279 perft 6 507140861 -id 1 +id 214 epd 1qbrknrb/1p1ppppp/1np5/8/p4P1P/4P1N1/PPPP2P1/NQBRK1RB w GDgd - 0 9 perft 1 21 perft 2 482 @@ -1935,7 +1936,7 @@ perft 4 267935 perft 5 6218644 perft 6 168704845 -id 1 +id 215 epd nbqrbkr1/ppp1pppp/8/3p4/6n1/2P2PPN/PP1PP2P/NBQRBK1R w HDd - 1 9 perft 1 29 perft 2 921 @@ -1944,7 +1945,7 @@ perft 4 840262 perft 5 24138518 perft 6 806554650 -id 1 +id 216 epd nqrb1knr/1ppbpp1p/p7/3p2p1/2P3P1/5P1P/PP1PP3/NQRBBKNR w HChc - 1 9 perft 1 31 perft 2 803 @@ -1953,7 +1954,7 @@ perft 4 665799 perft 5 21998733 perft 6 583349773 -id 1 +id 217 epd 1qrkbbr1/pppp1ppp/1n3n2/4p3/5P2/1N6/PPPPP1PP/1QRKBBNR w HCc - 0 9 perft 1 25 perft 2 715 @@ -1962,7 +1963,7 @@ perft 4 556325 perft 5 15514933 perft 6 459533767 -id 1 +id 218 epd nqrkb1rb/pp2pppp/2p1n3/3p4/3PP1N1/8/PPP2PPP/NQRKB1RB w GCgc - 0 9 perft 1 26 perft 2 795 @@ -1971,7 +1972,7 @@ perft 4 679387 perft 5 19185851 perft 6 616508881 -id 1 +id 219 epd nb1rknbr/pp2ppp1/8/2Bp3p/6P1/2P2P1q/PP1PP2P/NBQRKN1R w HDhd - 0 9 perft 1 35 perft 2 1391 @@ -1980,7 +1981,7 @@ perft 4 1726888 perft 5 53033675 perft 6 2139267832 -id 1 +id 220 epd nqrbkn1r/pp1pp1pp/8/2p2p2/5P2/P3B2P/1PbPP1P1/NQRBKN1R w HChc - 0 9 perft 1 23 perft 2 758 @@ -1989,7 +1990,7 @@ perft 4 653854 perft 5 18296195 perft 6 628403401 -id 1 +id 221 epd nqrknbbr/pp1pppp1/7p/2p5/7P/1P1N4/P1PPPPPB/NQRK1B1R w HChc - 2 9 perft 1 29 perft 2 824 @@ -1998,7 +1999,7 @@ perft 4 683686 perft 5 19429491 perft 6 595493802 -id 1 +id 222 epd 1qrknrbb/B1p1pppp/8/1p1p4/2n2P2/1P6/P1PPP1PP/NQRKNR1B w FCfc - 0 9 perft 1 28 perft 2 771 @@ -2007,7 +2008,7 @@ perft 4 581721 perft 5 16065378 perft 6 483037840 -id 1 +id 223 epd bbnrqk1r/1ppppppp/8/7n/1p6/P6P/1BPPPPP1/1BNRQKNR w HDhd - 0 9 perft 1 25 perft 2 601 @@ -2016,7 +2017,7 @@ perft 4 396661 perft 5 10697065 perft 6 289472497 -id 1 +id 224 epd bnrbqknr/ppp3p1/3ppp1Q/7p/3P4/1P6/P1P1PPPP/BNRB1KNR w HChc - 0 9 perft 1 32 perft 2 845 @@ -2025,7 +2026,7 @@ perft 4 742888 perft 5 23717883 perft 6 682154649 -id 1 +id 225 epd bn1qkb1r/pprppppp/8/2p5/2PPP1n1/8/PPR2PPP/BN1QKBNR w Hh - 1 9 perft 1 32 perft 2 856 @@ -2034,7 +2035,7 @@ perft 4 768595 perft 5 25245957 perft 6 727424329 -id 1 +id 226 epd 1nrqknrb/p1pp1ppp/1p2p3/3N4/5P1P/5b2/PPPPP3/B1RQKNRB w GCgc - 2 9 perft 1 33 perft 2 873 @@ -2043,7 +2044,7 @@ perft 4 779473 perft 5 25128076 perft 6 745401024 -id 1 +id 227 epd nbbrqrk1/pppppppp/8/2N1n3/P7/6P1/1PPPPP1P/1BBRQKNR w HD - 3 9 perft 1 25 perft 2 555 @@ -2052,7 +2053,7 @@ perft 4 342296 perft 5 9153089 perft 6 234841945 -id 1 +id 228 epd 1rbbqknr/1ppp1pp1/1n2p3/p6p/4P1P1/P6N/1PPP1P1P/NRBBQK1R w HBhb - 0 9 perft 1 25 perft 2 693 @@ -2061,7 +2062,7 @@ perft 4 528070 perft 5 15133381 perft 6 439344945 -id 1 +id 229 epd nrq1kbnr/p1pbpppp/3p4/1p6/6P1/1N3N2/PPPPPP1P/1RBQKB1R w HBhb - 4 9 perft 1 24 perft 2 648 @@ -2070,7 +2071,7 @@ perft 4 471192 perft 5 12871967 perft 6 380436777 -id 1 +id 230 epd nr1qknr1/p1pppp1p/b5p1/1p6/8/P4PP1/1bPPP1RP/NRBQKN1B w Bgb - 0 9 perft 1 18 perft 2 533 @@ -2079,7 +2080,7 @@ perft 4 331243 perft 5 7777833 perft 6 234905172 -id 1 +id 231 epd nbrqbknr/1ppp2pp/8/4pp2/p2PP1P1/7N/PPP2P1P/NBRQBK1R w HChc - 0 9 perft 1 29 perft 2 803 @@ -2088,7 +2089,7 @@ perft 4 706648 perft 5 22305910 perft 6 672322762 -id 1 +id 232 epd nr1b1k1r/ppp1pppp/2bp1n2/6P1/2P3q1/5P2/PP1PP2P/NRQBBKNR w HBhb - 1 9 perft 1 27 perft 2 1199 @@ -2097,7 +2098,7 @@ perft 4 1296241 perft 5 35121759 perft 6 1418677099 -id 1 +id 233 epd nrqkbbnr/2pppp1p/p7/1p6/2P1Pp2/8/PPNP2PP/1RQKBBNR w HBhb - 0 9 perft 1 28 perft 2 613 @@ -2106,7 +2107,7 @@ perft 4 432750 perft 5 13097064 perft 6 345294379 -id 1 +id 234 epd 1rqkbnrb/pp1ppp1p/1n4p1/B1p5/3PP3/4N3/PPP2PPP/NRQK2RB w GBgb - 0 9 perft 1 33 perft 2 723 @@ -2115,7 +2116,7 @@ perft 4 590970 perft 5 19715083 perft 6 535650233 -id 1 +id 235 epd nbrqkn1r/1pppp2p/5pp1/p2b4/5P2/P2PN3/1PP1P1PP/NBRQK1BR w HChc - 2 9 perft 1 23 perft 2 607 @@ -2124,7 +2125,7 @@ perft 4 400970 perft 5 11026383 perft 6 290708878 -id 1 +id 236 epd nrqbknbr/pp1pppp1/8/2p4p/P3PP2/8/1PPP2PP/NRQBKNBR w HBhb - 1 9 perft 1 26 perft 2 700 @@ -2133,7 +2134,7 @@ perft 4 556026 perft 5 16058815 perft 6 485460242 -id 1 +id 237 epd nrqknbbr/p2pppp1/1pp5/6Qp/3P4/1P3P2/P1P1P1PP/NR1KNBBR w HBhb - 0 9 perft 1 40 perft 2 905 @@ -2142,7 +2143,7 @@ perft 4 829746 perft 5 29263502 perft 6 791963709 -id 1 +id 238 epd nrqknrbb/1p3ppp/p2p4/2p1p3/1P6/3PP1P1/P1P2P1P/NRQKNRBB w FBfb - 0 9 perft 1 29 perft 2 780 @@ -2151,7 +2152,7 @@ perft 4 654495 perft 5 19532077 perft 6 593181101 -id 1 +id 239 epd 1bnrkqnr/p1pppp2/7p/1p4p1/4b3/7N/PPPP1PPP/BBNRKQ1R w HDhd - 0 9 perft 1 25 perft 2 725 @@ -2160,7 +2161,7 @@ perft 4 565006 perft 5 16661676 perft 6 487354613 -id 1 +id 240 epd bnrbkq1r/pp2p1pp/5n2/2pp1p2/P7/N1PP4/1P2PPPP/B1RBKQNR w HChc - 1 9 perft 1 24 perft 2 745 @@ -2169,7 +2170,7 @@ perft 4 584015 perft 5 15079602 perft 6 488924040 -id 1 +id 241 epd 2rkqbnr/p1pppppp/2b5/1pn5/1P3P1Q/2B5/P1PPP1PP/1NRK1BNR w HChc - 3 9 perft 1 33 perft 2 904 @@ -2178,7 +2179,7 @@ perft 4 840025 perft 5 28194726 perft 6 801757709 -id 1 +id 242 epd bnrkqnrb/2pppp2/8/pp4pp/1P5P/6P1/P1PPPPB1/BNRKQNR1 w GCgc - 0 9 perft 1 34 perft 2 1059 @@ -2187,7 +2188,7 @@ perft 4 1054311 perft 5 33195397 perft 6 1036498304 -id 1 +id 243 epd 1bbrkq1r/pppp2pp/1n2pp1n/8/2PP4/1N4P1/PP2PP1P/1BBRKQNR w HDhd - 1 9 perft 1 33 perft 2 891 @@ -2196,7 +2197,7 @@ perft 4 814247 perft 5 26970098 perft 6 788040469 -id 1 +id 244 epd nrbbkqnr/1p2pp1p/p1p3p1/3p4/8/1PP5/P2PPPPP/NRBBKQNR w HBhb - 0 9 perft 1 21 perft 2 567 @@ -2205,7 +2206,7 @@ perft 4 376487 perft 5 9539687 perft 6 284426039 -id 1 +id 245 epd 1rbkqbr1/ppp1pppp/1n5n/3p4/3P4/1PP3P1/P3PP1P/NRBKQBNR w HBb - 1 9 perft 1 27 perft 2 752 @@ -2214,7 +2215,7 @@ perft 4 606783 perft 5 16986290 perft 6 521817800 -id 1 +id 246 epd nrbkq1rb/1ppp1pp1/4p1n1/p6p/2PP4/5P2/PPK1P1PP/NRB1QNRB w gb - 0 9 perft 1 35 perft 2 697 @@ -2223,7 +2224,7 @@ perft 4 505836 perft 5 16906409 perft 6 390324794 -id 1 +id 247 epd nbrkbqnr/p2pp1p1/5p2/1pp4p/7P/3P2P1/PPP1PP2/NBKRBQNR w hc - 0 9 perft 1 25 perft 2 679 @@ -2232,7 +2233,7 @@ perft 4 484921 perft 5 12879258 perft 6 376652259 -id 1 +id 248 epd nrkb1qnr/ppppp1p1/6bp/5p2/1PP1P1P1/8/P2P1P1P/NRKBBQNR w HBhb - 1 9 perft 1 32 perft 2 761 @@ -2241,7 +2242,7 @@ perft 4 632916 perft 5 20671433 perft 6 568524724 -id 1 +id 249 epd nrk1bbnr/p1q1pppp/1ppp4/8/3P3P/4K3/PPP1PPP1/NR1QBBNR w hb - 0 9 perft 1 30 perft 2 719 @@ -2250,7 +2251,7 @@ perft 4 541389 perft 5 16278120 perft 6 423649784 -id 1 +id 250 epd nrkqbr1b/1pppp1pp/5pn1/p6N/1P3P2/8/P1PPP1PP/NRKQB1RB w GBb - 0 9 perft 1 26 perft 2 494 @@ -2259,7 +2260,7 @@ perft 4 296170 perft 5 8763742 perft 6 206993496 -id 1 +id 251 epd nbrkq2r/pppp1bpp/4p1n1/5p2/7P/2P3N1/PP1PPPP1/NBKRQ1BR w hc - 0 9 perft 1 27 perft 2 701 @@ -2268,7 +2269,7 @@ perft 4 535052 perft 5 15394667 perft 6 443506342 -id 1 +id 252 epd nrkbqnbr/2ppp2p/pp6/5pp1/P1P5/8/1P1PPPPP/NRKBQNBR w HBhb - 0 9 perft 1 21 perft 2 487 @@ -2277,7 +2278,7 @@ perft 4 285387 perft 5 7218486 perft 6 193586674 -id 1 +id 253 epd nr1qnbbr/pk1pppp1/1pp4p/8/3P4/5P1P/PPP1P1P1/NRKQNBBR w HB - 0 9 perft 1 22 perft 2 546 @@ -2286,7 +2287,7 @@ perft 4 352855 perft 5 9587439 perft 6 259830255 -id 1 +id 254 epd nrkq1rbb/pp1ppp1p/2pn4/8/PP3Pp1/7P/2PPP1P1/NRKQNRBB w FBfb - 0 9 perft 1 26 perft 2 839 @@ -2295,7 +2296,7 @@ perft 4 723845 perft 5 19867117 perft 6 658535326 -id 1 +id 255 epd b2rknqr/pp1ppppp/8/2P5/n7/P7/1PPNPPPb/BBNRK1QR w HDhd - 2 9 perft 1 24 perft 2 699 @@ -2304,7 +2305,7 @@ perft 4 575172 perft 5 17734818 perft 6 535094237 -id 1 +id 256 epd bnrbknqr/pp2p2p/2p3p1/3p1p2/8/3P4/PPPNPPPP/B1RBKNQR w HChc - 0 9 perft 1 23 perft 2 580 @@ -2313,7 +2314,7 @@ perft 4 385917 perft 5 10133092 perft 6 288041554 -id 1 +id 257 epd bnrknb1r/pppp2pp/8/4pp2/6P1/3P3P/qPP1PPQ1/BNRKNB1R w HChc - 0 9 perft 1 28 perft 2 1100 @@ -2322,7 +2323,7 @@ perft 4 1217514 perft 5 36142423 perft 6 1361341249 -id 1 +id 258 epd b1rknqrb/ppp1p1p1/2np1p1p/8/4N3/6PQ/PPPPPP1P/B1RKN1RB w GCgc - 0 9 perft 1 36 perft 2 629 @@ -2331,7 +2332,7 @@ perft 4 453064 perft 5 16897544 perft 6 367503974 -id 1 +id 259 epd nb1rknqr/pbppp2p/6p1/1p3p2/5P2/3KP3/PPPP2PP/NBBR1NQR w hd - 2 9 perft 1 18 perft 2 557 @@ -2340,7 +2341,7 @@ perft 4 300744 perft 5 5822387 perft 6 180936551 -id 1 +id 260 epd nr1bknqr/1ppb1ppp/p7/3pp3/B7/2P3NP/PP1PPPP1/NRB1K1QR w HBhb - 2 9 perft 1 28 perft 2 688 @@ -2349,7 +2350,7 @@ perft 4 519785 perft 5 15153092 perft 6 425149249 -id 1 +id 261 epd nrbkn2r/pppp1pqp/4p1p1/8/3P2P1/P3B3/P1P1PP1P/NR1KNBQR w HBhb - 1 9 perft 1 32 perft 2 808 @@ -2358,7 +2359,7 @@ perft 4 676525 perft 5 22094260 perft 6 609377239 -id 1 +id 262 epd nrbknqrb/2p1ppp1/1p6/p2p2Bp/1P6/3P1P2/P1P1P1PP/NR1KNQRB w GBgb - 0 9 perft 1 30 perft 2 625 @@ -2367,7 +2368,7 @@ perft 4 418895 perft 5 12225742 perft 6 301834282 -id 1 +id 263 epd nbr1knqr/1pp1p1pp/3p1pb1/8/7P/5P2/PPPPPQP1/NBRKBN1R w HC - 2 9 perft 1 29 perft 2 863 @@ -2376,7 +2377,7 @@ perft 4 800239 perft 5 24965592 perft 6 799182442 -id 1 +id 264 epd n1kbbnqr/prp2ppp/1p1p4/4p3/1P2P3/3P1B2/P1P2PPP/NRK1BNQR w HBh - 2 9 perft 1 26 perft 2 653 @@ -2385,7 +2386,7 @@ perft 4 449719 perft 5 12187583 perft 6 336872952 -id 1 +id 265 epd nrknbbqr/pp3p1p/B3p1p1/2pp4/4P3/2N3P1/PPPP1P1P/NRK1B1QR w HBhb - 0 9 perft 1 29 perft 2 683 @@ -2394,7 +2395,7 @@ perft 4 501807 perft 5 14684565 perft 6 394951291 -id 1 +id 266 epd n1knbqrb/pr1p1ppp/Qp6/2p1p3/4P3/6P1/PPPP1P1P/NRKNB1RB w GBg - 2 9 perft 1 31 perft 2 552 @@ -2403,7 +2404,7 @@ perft 4 371343 perft 5 11663330 perft 6 283583340 -id 1 +id 267 epd nbrknqbr/p3p1pp/1p1p1p2/2p5/2Q1PP2/8/PPPP2PP/NBRKN1BR w HChc - 0 9 perft 1 37 perft 2 913 @@ -2412,7 +2413,7 @@ perft 4 825748 perft 5 28899548 perft 6 759875563 -id 1 +id 268 epd nrkb1qbr/pp1pppp1/5n2/7p/2p5/1N1NPP2/PPPP2PP/1RKB1QBR w HBhb - 0 9 perft 1 25 perft 2 712 @@ -2421,7 +2422,7 @@ perft 4 543870 perft 5 15045589 perft 6 445074372 -id 1 +id 269 epd nrk2bbr/pppqpppp/3p4/8/1P3nP1/3P4/P1P1PP1P/NRKNQBBR w HBhb - 1 9 perft 1 24 perft 2 814 @@ -2430,7 +2431,7 @@ perft 4 670162 perft 5 17603960 perft 6 592121050 -id 1 +id 270 epd nrknqrbb/1p2ppp1/2pp4/Q6p/P2P3P/8/1PP1PPP1/NRKN1RBB w FBfb - 0 9 perft 1 34 perft 2 513 @@ -2439,7 +2440,7 @@ perft 4 303908 perft 5 9569590 perft 6 206509331 -id 1 +id 271 epd bbnrk1rq/pp2p1pp/2ppn3/5p2/8/3NNP1P/PPPPP1P1/BB1RK1RQ w GDgd - 1 9 perft 1 28 perft 2 697 @@ -2448,7 +2449,7 @@ perft 4 517917 perft 5 15301879 perft 6 410843713 -id 1 +id 272 epd bnrbknrq/ppppp2p/6p1/5p2/4QPP1/8/PPPPP2P/BNRBKNR1 w GCgc - 0 9 perft 1 37 perft 2 901 @@ -2457,7 +2458,7 @@ perft 4 877372 perft 5 31385912 perft 6 903831981 -id 1 +id 273 epd bnkrnbrq/ppppp1p1/B6p/5p2/8/4P3/PPPP1PPP/BNKRN1RQ w - - 0 9 perft 1 26 perft 2 417 @@ -2466,7 +2467,7 @@ perft 4 217095 perft 5 5980981 perft 6 133080499 -id 1 +id 274 epd bnrk1rqb/2pppp1p/3n4/pp4p1/3Q1P2/2N3P1/PPPPP2P/B1RKNR1B w FCfc - 0 9 perft 1 49 perft 2 1655 @@ -2475,7 +2476,7 @@ perft 4 2512003 perft 5 107234294 perft 6 3651608327 -id 1 +id 275 epd nbbrk1rq/pp2pppp/2pp4/8/2P2n2/6N1/PP1PP1PP/NBBRKR1Q w Dgd - 0 9 perft 1 28 perft 2 960 @@ -2484,7 +2485,7 @@ perft 4 884237 perft 5 26083252 perft 6 846682836 -id 1 +id 276 epd nrbb2rq/pppk1ppp/4p1n1/3p4/6P1/1BP5/PP1PPPQP/NRB1KNR1 w GB - 0 9 perft 1 28 perft 2 735 @@ -2493,7 +2494,7 @@ perft 4 593839 perft 5 18588316 perft 6 512048946 -id 1 +id 277 epd nrbk1brq/p1ppppp1/7p/1p6/4P1nP/P7/1PPP1PP1/NRBKNBRQ w GBgb - 0 9 perft 1 22 perft 2 572 @@ -2502,7 +2503,7 @@ perft 4 351494 perft 5 8525056 perft 6 247615348 -id 1 +id 278 epd nrbk1rqb/1pp2ppp/5n2/p2pp3/5B2/1N1P2P1/PPP1PP1P/1R1KNRQB w FBfb - 0 9 perft 1 35 perft 2 927 @@ -2511,7 +2512,7 @@ perft 4 849932 perft 5 28465693 perft 6 783048748 -id 1 +id 279 epd nbrkb1rq/p1pp1ppp/4n3/4p3/Pp6/6N1/1PPPPPPP/NBRKBRQ1 w Cgc - 0 9 perft 1 20 perft 2 456 @@ -2520,7 +2521,7 @@ perft 4 247733 perft 5 6124625 perft 6 154766108 -id 1 +id 280 epd nrkb1nrq/p2pp1pp/1pp2p2/7b/6PP/5P2/PPPPP2N/NRKBB1RQ w GBgb - 0 9 perft 1 21 perft 2 479 @@ -2529,7 +2530,7 @@ perft 4 264493 perft 5 6696458 perft 6 165253524 -id 1 +id 281 epd nr1nbbr1/pppkpp1p/6p1/3p4/P6P/1P6/1RPPPPP1/N1KNBBRQ w G - 1 9 perft 1 20 perft 2 498 @@ -2538,7 +2539,7 @@ perft 4 288813 perft 5 7197322 perft 6 188021682 -id 1 +id 282 epd nrknbrqb/3p1ppp/ppN1p3/8/6P1/8/PPPPPP1P/1RKNBRQB w FBfb - 0 9 perft 1 32 perft 2 526 @@ -2547,7 +2548,7 @@ perft 4 319836 perft 5 10755190 perft 6 220058991 -id 1 +id 283 epd nbrkn1bq/p1pppr1p/1p6/5pp1/8/1N2PP2/PPPP2PP/1BKRNRBQ w c - 1 9 perft 1 19 perft 2 491 @@ -2556,7 +2557,7 @@ perft 4 277313 perft 5 6230616 perft 6 180748649 -id 1 +id 284 epd nrkbnrbq/ppppppp1/8/8/7p/PP3P2/2PPPRPP/NRKBN1BQ w Bfb - 0 9 perft 1 16 perft 2 353 @@ -2565,7 +2566,7 @@ perft 4 156002 perft 5 3008668 perft 6 82706705 -id 1 +id 285 epd nrknrbbq/p4ppp/2p1p3/1p1p4/1P2P3/2P5/P1NP1PPP/1RKNRBBQ w EBeb - 0 9 perft 1 29 perft 2 728 @@ -2574,7 +2575,7 @@ perft 4 587668 perft 5 18231199 perft 6 511686397 -id 1 +id 286 epd nrknr1bb/pppp1p2/7p/2qPp1p1/8/1P5P/P1P1PPP1/NRKNRQBB w EBeb - 0 9 perft 1 20 perft 2 714 @@ -2583,7 +2584,7 @@ perft 4 500458 perft 5 11132758 perft 6 386064577 -id 1 +id 287 epd bbqnrrkn/ppp2p1p/3pp1p1/8/1PP5/2Q5/P1BPPPPP/B2NRKRN w GE - 0 9 perft 1 39 perft 2 593 @@ -2592,7 +2593,7 @@ perft 4 424799 perft 5 16764576 perft 6 346185058 -id 1 +id 288 epd bqn1rkrn/p1p2ppp/1p1p4/4p3/3PP2b/8/PPP2PPP/BQNBRKRN w GEge - 2 9 perft 1 25 perft 2 773 @@ -2601,7 +2602,7 @@ perft 4 616817 perft 5 16632403 perft 6 515838333 -id 1 +id 289 epd bqnrkb1n/p1p1pprp/3p4/1p2P1p1/2PP4/8/PP3PPP/BQNRKBRN w GDd - 1 9 perft 1 31 perft 2 860 @@ -2610,7 +2611,7 @@ perft 4 810379 perft 5 27233018 perft 6 813751250 -id 1 +id 290 epd bqr1krnb/ppppppp1/7p/3n4/1P4P1/P4N2/2PPPP1P/BQNRKR1B w FDf - 3 9 perft 1 31 perft 2 709 @@ -2619,7 +2620,7 @@ perft 4 559830 perft 5 18608857 perft 6 480498340 -id 1 +id 291 epd qbbn1krn/pp3ppp/4r3/2ppp3/P1P4P/8/1P1PPPP1/QBBNRKRN w GEg - 1 9 perft 1 26 perft 2 775 @@ -2628,7 +2629,7 @@ perft 4 649673 perft 5 18476807 perft 6 582542257 -id 1 +id 292 epd qnbbrkrn/1p1pp2p/p7/2p2pp1/8/4P2P/PPPP1PPK/QNBBRR1N w ge - 0 9 perft 1 25 perft 2 599 @@ -2637,7 +2638,7 @@ perft 4 389104 perft 5 10260500 perft 6 279222412 -id 1 +id 293 epd qnbrkbrn/1ppp2p1/p3p2p/5p2/P4P2/1P6/2PPP1PP/QNBRKBRN w GDgd - 0 9 perft 1 27 perft 2 588 @@ -2646,7 +2647,7 @@ perft 4 394829 perft 5 11640416 perft 6 293541380 -id 1 +id 294 epd 1nbrkrnb/p1pppp1p/1pq3p1/8/4P3/P1P4N/1P1P1PPP/QNBRKR1B w FDfd - 1 9 perft 1 18 perft 2 609 @@ -2655,7 +2656,7 @@ perft 4 406831 perft 5 8604788 perft 6 299491047 -id 1 +id 295 epd qb1r1krn/pppp2pp/1n2ppb1/4P3/7P/8/PPPP1PP1/QBNRBKRN w GDgd - 0 9 perft 1 20 perft 2 578 @@ -2664,7 +2665,7 @@ perft 4 349453 perft 5 7939483 perft 6 229142178 -id 1 +id 296 epd qnr1bkrn/p3pppp/1bpp4/1p6/2P2PP1/8/PP1PPN1P/QNRBBKR1 w GCgc - 0 9 perft 1 30 perft 2 865 @@ -2673,7 +2674,7 @@ perft 4 771705 perft 5 24475596 perft 6 719842237 -id 1 +id 297 epd 1nkrbbrn/qppppppp/8/8/p2P4/1P5P/P1P1PPP1/QNKRBBRN w - - 0 9 perft 1 27 perft 2 672 @@ -2682,7 +2683,7 @@ perft 4 505278 perft 5 14065717 perft 6 410130412 -id 1 +id 298 epd 1qrkbrnb/ppp1p1pp/n2p4/5p2/4N3/8/PPPPPPPP/Q1RKBRNB w Ffc - 2 9 perft 1 25 perft 2 718 @@ -2691,7 +2692,7 @@ perft 4 536771 perft 5 14404324 perft 6 424279467 -id 1 +id 299 epd q1nrkrbn/pp1pppp1/2p4p/8/P7/5Pb1/BPPPPNPP/Q1NRKRB1 w FDfd - 0 9 perft 1 22 perft 2 558 @@ -2700,7 +2701,7 @@ perft 4 336042 perft 5 8516966 perft 6 228074630 -id 1 +id 300 epd qnrbkrbn/1p1p1pp1/p1p5/4p2p/8/3P1P2/PPP1P1PP/QNRBKRBN w FCfc - 0 9 perft 1 28 perft 2 669 @@ -2709,7 +2710,7 @@ perft 4 440930 perft 5 12055174 perft 6 313276304 -id 1 +id 301 epd qnrkr1bn/p1pp1ppp/8/1p2p3/3P1P2/bP4P1/P1P1P2P/QNRKRBBN w ECec - 1 9 perft 1 23 perft 2 845 @@ -2718,7 +2719,7 @@ perft 4 759778 perft 5 19939053 perft 6 718075943 -id 1 +id 302 epd q1krrnbb/p1p1pppp/2np4/1pB5/5P2/8/PPPPP1PP/QNRKRN1B w EC - 0 9 perft 1 29 perft 2 776 @@ -2727,7 +2728,7 @@ perft 4 631941 perft 5 18110831 perft 6 549019739 -id 1 +id 303 epd bbn1rkrn/pp1p1ppp/8/2p1p1q1/6P1/P7/BPPPPP1P/B1NQRKRN w GEge - 0 9 perft 1 26 perft 2 936 @@ -2736,7 +2737,7 @@ perft 4 906801 perft 5 24984621 perft 6 901444251 -id 1 +id 304 epd bn1brkrn/pp1qpp1p/2p3p1/3p4/1PPP4/P7/4PPPP/BNQBRKRN w GEge - 1 9 perft 1 29 perft 2 755 @@ -2745,7 +2746,7 @@ perft 4 645963 perft 5 20128587 perft 6 600207069 -id 1 +id 305 epd b2rkbrn/p1pppppp/qp6/8/1n6/2B2P2/P1PPP1PP/1NQRKBRN w GDgd - 0 9 perft 1 24 perft 2 878 @@ -2754,7 +2755,7 @@ perft 4 791007 perft 5 20840078 perft 6 775795187 -id 1 +id 306 epd b2rkrnb/pqp1pppp/n7/1p1p4/P7/N1P2N2/1P1PPPPP/B1QRKR1B w FDfd - 4 9 perft 1 26 perft 2 724 @@ -2763,7 +2764,7 @@ perft 4 571891 perft 5 16109522 perft 6 492933398 -id 1 +id 307 epd 1bbqrkrn/ppppp1p1/8/5p1p/P1n3P1/3P4/1PP1PP1P/NBBQRRKN w ge - 1 9 perft 1 25 perft 2 678 @@ -2772,7 +2773,7 @@ perft 4 461211 perft 5 12173245 perft 6 329661421 -id 1 +id 308 epd nqb1rrkn/ppp1bppp/3pp3/8/3P4/1P6/PQP1PPPP/N1BBRRKN w - - 1 9 perft 1 23 perft 2 503 @@ -2781,7 +2782,7 @@ perft 4 290341 perft 5 7626054 perft 6 188215608 -id 1 +id 309 epd nqbrkbr1/p1pppppp/1p6/2N2n2/2P5/5P2/PP1PP1PP/1QBRKBRN w GDgd - 1 9 perft 1 29 perft 2 688 @@ -2790,7 +2791,7 @@ perft 4 506302 perft 5 15167248 perft 6 399015237 -id 1 +id 310 epd nqbrkrn1/1ppppp2/6pp/p7/1P6/2Q5/P1PPPPPP/N1BRKRNB w FDfd - 0 9 perft 1 36 perft 2 602 @@ -2799,7 +2800,7 @@ perft 4 397340 perft 5 13706856 perft 6 291708797 -id 1 +id 311 epd nbqrbrkn/pp1p1pp1/2p5/4p2p/2P3P1/1P3P2/P2PP2P/NBQRBKRN w GD - 0 9 perft 1 34 perft 2 655 @@ -2808,7 +2809,7 @@ perft 4 474396 perft 5 16613630 perft 6 379344541 -id 1 +id 312 epd nqrbbrkn/1p1pppp1/8/p1p4p/4P2P/1N4P1/PPPP1P2/1QRBBKRN w GC - 0 9 perft 1 23 perft 2 597 @@ -2817,7 +2818,7 @@ perft 4 400357 perft 5 10096863 perft 6 294900903 -id 1 +id 313 epd nqrkbbrn/2p1p1pp/pp1p1p2/8/P2N4/2P5/1P1PPPPP/1QRKBBRN w GCgc - 0 9 perft 1 32 perft 2 744 @@ -2826,7 +2827,7 @@ perft 4 550728 perft 5 17597164 perft 6 428786656 -id 1 +id 314 epd n1krbrnb/q1pppppp/p7/1p6/3Q4/2P2P2/PP1PP1PP/N1RKBRNB w FC - 1 9 perft 1 43 perft 2 1038 @@ -2835,7 +2836,7 @@ perft 4 1074450 perft 5 40918952 perft 6 1126603824 -id 1 +id 315 epd nb1rkrbn/p1pp1p1p/qp6/4p1p1/5PP1/P7/1PPPPB1P/NBQRKR1N w FDfd - 2 9 perft 1 26 perft 2 645 @@ -2844,7 +2845,7 @@ perft 4 445464 perft 5 11911314 perft 6 342563372 -id 1 +id 316 epd nqr1krbn/pppp1ppp/8/8/3pP3/5P2/PPPb1NPP/NQRBKRB1 w FCfc - 3 9 perft 1 2 perft 2 51 @@ -2853,7 +2854,7 @@ perft 4 27743 perft 5 612305 perft 6 17040200 -id 1 +id 317 epd n1rkrbbn/pqppppp1/7p/1p6/8/1NPP4/PP1KPPPP/1QR1RBBN w ec - 0 9 perft 1 25 perft 2 674 @@ -2862,7 +2863,7 @@ perft 4 505337 perft 5 13421727 perft 6 403551903 -id 1 +id 318 epd 1qrkrnbb/1p1p1ppp/pnp1p3/8/3PP3/P6P/1PP2PP1/NQRKRNBB w ECec - 0 9 perft 1 24 perft 2 688 @@ -2871,7 +2872,7 @@ perft 4 511444 perft 5 13322502 perft 6 403441498 -id 1 +id 319 epd 1bnrqkrn/2ppppp1/p7/1p1b3p/3PP1P1/8/PPPQ1P1P/BBNR1KRN w GDgd - 1 9 perft 1 35 perft 2 925 @@ -2880,7 +2881,7 @@ perft 4 857060 perft 5 30458921 perft 6 824344087 -id 1 +id 320 epd bnrbqkr1/ppp2pp1/6n1/3pp2p/1P6/2N3N1/P1PPPPPP/B1RBQRK1 w gc - 0 9 perft 1 23 perft 2 704 @@ -2889,7 +2890,7 @@ perft 4 539587 perft 5 14154852 perft 6 450893738 -id 1 +id 321 epd 1nrqkbrn/p1pppppp/8/1p1b4/P6P/5P2/1PPPP1P1/BNRQKBRN w GCgc - 1 9 perft 1 19 perft 2 505 @@ -2898,7 +2899,7 @@ perft 4 281422 perft 5 6450025 perft 6 175593967 -id 1 +id 322 epd b1rqkrnb/ppppppp1/8/6p1/3n4/NP6/P1PPPP1P/B1RQKRNB w FCfc - 0 9 perft 1 25 perft 2 614 @@ -2907,7 +2908,7 @@ perft 4 377660 perft 5 10391021 perft 6 259629603 -id 1 +id 323 epd nbbrqkrn/ppp3p1/3pp3/5p1p/1P2P3/P7/2PPQPPP/NBBR1KRN w GDgd - 0 9 perft 1 30 perft 2 833 @@ -2916,7 +2917,7 @@ perft 4 717713 perft 5 22873901 perft 6 649556666 -id 1 +id 324 epd nr1bqrk1/ppp1pppp/6n1/3pP3/8/5PQb/PPPP2PP/NRBB1KRN w GB - 3 9 perft 1 26 perft 2 734 @@ -2925,7 +2926,7 @@ perft 4 582591 perft 5 17199594 perft 6 512134836 -id 1 +id 325 epd 1rbqkbr1/ppppp1pp/1n6/4np2/3P1P2/6P1/PPPQP2P/NRB1KBRN w GBgb - 1 9 perft 1 27 perft 2 662 @@ -2934,7 +2935,7 @@ perft 4 447464 perft 5 13038519 perft 6 338365642 -id 1 +id 326 epd nr1qkr1b/ppp1pp1p/4bn2/3p2p1/4P3/1Q6/PPPP1PPP/NRB1KRNB w FBfb - 4 9 perft 1 33 perft 2 939 @@ -2943,7 +2944,7 @@ perft 4 942138 perft 5 30995969 perft 6 991509814 -id 1 +id 327 epd nb1qbkrn/pprp1pp1/7p/2p1pB2/Q1PP4/8/PP2PPPP/N1R1BKRN w GCg - 2 9 perft 1 47 perft 2 1128 @@ -2952,7 +2953,7 @@ perft 4 1306753 perft 5 56747878 perft 6 1560584212 -id 1 +id 328 epd nrqb1rkn/pp2pppp/2bp4/2p5/6P1/2P3N1/PP1PPP1P/NRQBBRK1 w - - 3 9 perft 1 24 perft 2 828 @@ -2961,7 +2962,7 @@ perft 4 723705 perft 5 19506135 perft 6 668969549 -id 1 +id 329 epd nrq1bbrn/ppkpp2p/2p3p1/P4p2/8/4P1N1/1PPP1PPP/NRQKBBR1 w GB - 0 9 perft 1 25 perft 2 525 @@ -2970,7 +2971,7 @@ perft 4 309994 perft 5 8250997 perft 6 201795680 -id 1 +id 330 epd Br1kbrn1/pqpppp2/8/6pp/3b2P1/1N6/PPPPPP1P/1RQKBRN1 w FBfb - 3 9 perft 1 20 perft 2 790 @@ -2979,7 +2980,7 @@ perft 4 695905 perft 5 17735648 perft 6 669854148 -id 1 +id 331 epd nbrqkrbn/2p1p1pp/p7/1p1p1p2/4P1P1/5P2/PPPP3P/NBRQKRBN w FCfc - 0 9 perft 1 29 perft 2 771 @@ -2988,7 +2989,7 @@ perft 4 647106 perft 5 19192982 perft 6 591335970 -id 1 +id 332 epd 1rqbkrbn/1ppppp1p/1n6/p1N3p1/8/2P4P/PP1PPPP1/1RQBKRBN w FBfb - 0 9 perft 1 29 perft 2 502 @@ -2997,7 +2998,7 @@ perft 4 287739 perft 5 8652810 perft 6 191762235 -id 1 +id 333 epd 1rqkrbbn/ppnpp1pp/8/2p5/6p1/3P4/PPP1PPPP/NRK1RBBN w eb - 0 9 perft 1 19 perft 2 531 @@ -3006,7 +3007,7 @@ perft 4 300384 perft 5 6506674 perft 6 184309316 -id 1 +id 334 epd nrqkrnbb/p1pp2pp/5p2/4P3/2p5/4N3/PP1PP1PP/NRQKR1BB w EBeb - 0 9 perft 1 26 perft 2 800 @@ -3015,7 +3016,7 @@ perft 4 756695 perft 5 23952941 perft 6 809841274 -id 1 +id 335 epd bbnrkqrn/pp3pp1/4p2p/2pp4/4P1P1/1PB5/P1PP1P1P/1BNRKQRN w GDgd - 0 9 perft 1 33 perft 2 915 @@ -3024,7 +3025,7 @@ perft 4 878648 perft 5 29602610 perft 6 881898159 -id 1 +id 336 epd bnrbkqr1/1p2pppp/6n1/p1pp4/7P/P3P3/1PPPKPP1/BNRB1QRN w gc - 0 9 perft 1 19 perft 2 457 @@ -3033,7 +3034,7 @@ perft 4 238944 perft 5 5356253 perft 6 144653627 -id 1 +id 337 epd b1rkqbrn/pp1p2pp/2n1p3/2p2p2/3P2PP/8/PPP1PP2/BNKRQBRN w gc - 0 9 perft 1 30 perft 2 985 @@ -3042,7 +3043,7 @@ perft 4 1011700 perft 5 32684185 perft 6 1080607773 -id 1 +id 338 epd b1rkqrnb/2ppppp1/np6/p6p/1P6/P2P3P/2P1PPP1/BNRKQRNB w FCfc - 0 9 perft 1 26 perft 2 692 @@ -3051,7 +3052,7 @@ perft 4 517703 perft 5 14561181 perft 6 413226841 -id 1 +id 339 epd nbbrkqrn/1ppp1p2/p6p/4p1p1/5P2/1P5P/P1PPPNP1/NBBRKQR1 w GDgd - 0 9 perft 1 22 perft 2 561 @@ -3060,7 +3061,7 @@ perft 4 367487 perft 5 9307003 perft 6 273928315 -id 1 +id 340 epd nrbbkqrn/p1pppppp/8/1p6/4P3/7Q/PPPP1PPP/NRBBK1RN w GBgb - 0 9 perft 1 38 perft 2 769 @@ -3069,7 +3070,7 @@ perft 4 632310 perft 5 23091070 perft 6 560139600 -id 1 +id 341 epd nrbkqbrn/1pppp2p/8/p4pp1/P4PQ1/8/1PPPP1PP/NRBK1BRN w GBgb - 0 9 perft 1 23 perft 2 507 @@ -3078,7 +3079,7 @@ perft 4 321423 perft 5 8887567 perft 6 237475184 -id 1 +id 342 epd nr1kqr1b/pp2pppp/5n2/2pp4/P5b1/5P2/1PPPPRPP/NRBK1QNB w Bfb - 2 9 perft 1 18 perft 2 626 @@ -3087,7 +3088,7 @@ perft 4 434138 perft 5 9465555 perft 6 335004239 -id 1 +id 343 epd nbkrbqrn/1pppppp1/8/4P2p/pP6/P7/2PP1PPP/NBRKBQRN w GC - 0 9 perft 1 22 perft 2 329 @@ -3096,7 +3097,7 @@ perft 4 148351 perft 5 4160034 perft 6 82875306 -id 1 +id 344 epd nrkb1qrn/pp1pp1pp/8/5p1b/P1p4P/6N1/1PPPPPP1/NRKBBQR1 w GBgb - 2 9 perft 1 16 perft 2 479 @@ -3105,7 +3106,7 @@ perft 4 275354 perft 5 5862341 perft 6 184959796 -id 1 +id 345 epd 1rkq1brn/ppppp1pp/1n6/3b1p2/3N3P/5P2/PPPPP1P1/1RKQBBRN w GBgb - 3 9 perft 1 23 perft 2 614 @@ -3114,7 +3115,7 @@ perft 4 418395 perft 5 11090645 perft 6 313526088 -id 1 +id 346 epd nrk1brnb/pp1ppppp/2p5/3q4/5P2/PP6/1KPPP1PP/NR1QBRNB w fb - 1 9 perft 1 25 perft 2 942 @@ -3123,7 +3124,7 @@ perft 4 792179 perft 5 19318837 perft 6 685549171 -id 1 +id 347 epd nbrkqr1n/1pppp2p/p4pp1/2Bb4/5P2/6P1/PPPPP2P/NBRKQ1RN w Cfc - 2 9 perft 1 30 perft 2 841 @@ -3132,7 +3133,7 @@ perft 4 677876 perft 5 20145765 perft 6 557578726 -id 1 +id 348 epd n1kbqrbn/2p1pppp/1r6/pp1p4/P7/3P4/1PP1PPPP/NRKBQRBN w FBf - 2 9 perft 1 21 perft 2 591 @@ -3141,7 +3142,7 @@ perft 4 394289 perft 5 10295086 perft 6 292131422 -id 1 +id 349 epd nrkqrbb1/ppp1pppp/3p4/8/4P3/2Pn1P2/PP4PP/NRKQRBBN w EBeb - 0 9 perft 1 4 perft 2 88 @@ -3150,7 +3151,7 @@ perft 4 73414 perft 5 2640555 perft 6 66958031 -id 1 +id 350 epd nrkqrnbb/ppppp1p1/7p/1P3p2/3P4/2P5/P3PPPP/NRKQRNBB w EBeb - 0 9 perft 1 29 perft 2 689 @@ -3159,7 +3160,7 @@ perft 4 508789 perft 5 16226660 perft 6 408570219 -id 1 +id 351 epd bbnr1rqn/pp2pkpp/2pp1p2/8/4P1P1/8/PPPP1P1P/BBNRKRQN w FD - 0 9 perft 1 21 perft 2 463 @@ -3168,7 +3169,7 @@ perft 4 256244 perft 5 6826249 perft 6 165025370 -id 1 +id 352 epd bnrbk1qn/1pppprpp/8/p4p1P/6P1/3P4/PPP1PP2/BNRBKRQN w FCc - 0 9 perft 1 22 perft 2 459 @@ -3177,7 +3178,7 @@ perft 4 268157 perft 5 7371098 perft 6 190583454 -id 1 +id 353 epd 1nrkrbqn/p1pp1ppp/4p3/1p6/1PP5/6PB/P2PPPbP/BNRKR1QN w ECec - 0 9 perft 1 30 perft 2 931 @@ -3186,7 +3187,7 @@ perft 4 887414 perft 5 28412902 perft 6 869228014 -id 1 +id 354 epd b1rkr1nb/pppppqp1/n4B2/7p/8/1P4P1/P1PPPP1P/1NKRRQNB w ec - 1 9 perft 1 36 perft 2 934 @@ -3195,7 +3196,7 @@ perft 4 930926 perft 5 30392925 perft 6 952871799 -id 1 +id 355 epd nbbrkrqn/p1ppp1p1/8/1p3p1p/2P3PP/8/PP1PPPQ1/NBBRKR1N w FDfd - 0 9 perft 1 34 perft 2 938 @@ -3204,7 +3205,7 @@ perft 4 921716 perft 5 31185844 perft 6 944483246 -id 1 +id 356 epd 1rbbkrqn/ppp1pp2/1n1p2p1/7p/P3P1P1/3P4/1PP2P1P/NRBBKRQN w FBfb - 0 9 perft 1 26 perft 2 646 @@ -3213,7 +3214,7 @@ perft 4 472744 perft 5 14006203 perft 6 384101783 -id 1 +id 357 epd nrbkrbq1/Qpppp1pp/2n5/5p2/P4P2/6N1/1PPPP1PP/NRBKRB2 w EBeb - 1 9 perft 1 27 perft 2 619 @@ -3222,7 +3223,7 @@ perft 4 421845 perft 5 11718463 perft 6 313794027 -id 1 +id 358 epd 1rbkr1nb/pppp1qpp/1n6/4pp2/1PP1P3/8/PB1P1PPP/NR1KRQNB w EBeb - 1 9 perft 1 32 perft 2 1029 @@ -3231,7 +3232,7 @@ perft 4 1080977 perft 5 35483796 perft 6 1181835398 -id 1 +id 359 epd nbrk1rqn/p1ppp2p/1p6/5ppb/8/1N2P2P/PPPP1PP1/1BKRBRQN w fc - 0 9 perft 1 18 perft 2 594 @@ -3240,7 +3241,7 @@ perft 4 408544 perft 5 9329122 perft 6 315021712 -id 1 +id 360 epd nrkbbrqn/3pppp1/7p/ppp5/P7/1N5P/1PPPPPP1/1RKBBRQN w FBfb - 0 9 perft 1 19 perft 2 417 @@ -3249,7 +3250,7 @@ perft 4 218513 perft 5 5236331 perft 6 137024458 -id 1 +id 361 epd nrkr1bqn/ppp1pppp/3p4/1b6/7P/P7/1PPPPPP1/NRKRBBQN w DBdb - 1 9 perft 1 17 perft 2 457 @@ -3258,7 +3259,7 @@ perft 4 243872 perft 5 5503579 perft 6 150091997 -id 1 +id 362 epd nrkrbqnb/p4ppp/1p2p3/2pp4/6P1/2P2N2/PPNPPP1P/1RKRBQ1B w DBdb - 0 9 perft 1 27 perft 2 755 @@ -3267,7 +3268,7 @@ perft 4 620093 perft 5 17883987 perft 6 547233320 -id 1 +id 363 epd nbkrr1bn/ppB2ppp/4p3/2qp4/4P3/5P2/PPPP2PP/NBRKRQ1N w EC - 1 9 perft 1 37 perft 2 1473 @@ -3276,7 +3277,7 @@ perft 4 1956521 perft 5 68070015 perft 6 2490912491 -id 1 +id 364 epd n1kbrqbn/p1pp1pp1/4p2p/2B5/1r3P2/8/PPPPP1PP/NRKBRQ1N w EBe - 2 9 perft 1 30 perft 2 1029 @@ -3285,7 +3286,7 @@ perft 4 1053163 perft 5 32318550 perft 6 1106487743 -id 1 +id 365 epd nrkrqbbn/2pppp1p/8/pp6/1P1P2p1/P5P1/2P1PP1P/NRKRQBBN w DBdb - 0 9 perft 1 22 perft 2 421 @@ -3294,7 +3295,7 @@ perft 4 221927 perft 5 5754555 perft 6 141245633 -id 1 +id 366 epd nrkr1nbb/1ppp2pp/p3q3/4pp2/2P5/P3P3/1PKP1PPP/NR1RQNBB w db - 0 9 perft 1 22 perft 2 619 @@ -3303,7 +3304,7 @@ perft 4 411392 perft 5 9905109 perft 6 301403003 -id 1 +id 367 epd bbnrkrnq/1pp1p2p/6p1/p2p1p2/8/1P2P3/P1PP1PPP/BBNRKRNQ w FDfd - 0 9 perft 1 27 perft 2 805 @@ -3312,7 +3313,7 @@ perft 4 688224 perft 5 19133881 perft 6 620749189 -id 1 +id 368 epd bnrbkrn1/pp1ppp2/2p3pp/8/2Pq4/P4PP1/1P1PP2P/BNRBKRNQ w FCfc - 1 9 perft 1 20 perft 2 770 @@ -3321,7 +3322,7 @@ perft 4 577980 perft 5 13581691 perft 6 456736500 -id 1 +id 369 epd b1rkrbnq/1pp1pppp/2np4/p5N1/8/1P2P3/P1PP1PPP/BNRKRB1Q w ECec - 0 9 perft 1 37 perft 2 740 @@ -3330,7 +3331,7 @@ perft 4 581744 perft 5 21156664 perft 6 485803600 -id 1 +id 370 epd b1krrnqb/pp1ppp1p/n1p3p1/2N5/6P1/8/PPPPPP1P/B1RKRNQB w EC - 0 9 perft 1 34 perft 2 850 @@ -3339,7 +3340,7 @@ perft 4 752350 perft 5 25360295 perft 6 698159474 -id 1 +id 371 epd 1bbr1rnq/ppppkppp/8/3np3/4P3/3P4/PPP1KPPP/NBBRR1NQ w - - 1 9 perft 1 27 perft 2 704 @@ -3348,7 +3349,7 @@ perft 4 480474 perft 5 12817011 perft 6 341026662 -id 1 +id 372 epd nrbbk1nq/p1p1prpp/1p6/N2p1p2/P7/8/1PPPPPPP/R1BBKRNQ w Fb - 2 9 perft 1 23 perft 2 552 @@ -3357,7 +3358,7 @@ perft 4 348593 perft 5 9236564 perft 6 248469879 -id 1 +id 373 epd 1rbkrb1q/1pppp1pp/1n5n/p4p2/P3P3/1P6/2PPNPPP/NRBKRB1Q w EBeb - 1 9 perft 1 22 perft 2 415 @@ -3366,7 +3367,7 @@ perft 4 217224 perft 5 5735644 perft 6 135295774 -id 1 +id 374 epd nrbkr1qb/1pp1pppp/6n1/p2p4/2P1P3/1N4N1/PP1P1PPP/1RBKR1QB w EBeb - 0 9 perft 1 27 perft 2 709 @@ -3375,7 +3376,7 @@ perft 4 506214 perft 5 14192779 perft 6 380516508 -id 1 +id 375 epd nbrkbrnq/p3p1pp/1pp2p2/3p4/1PP5/4P3/P1KP1PPP/NBR1BRNQ w fc - 0 9 perft 1 24 perft 2 715 @@ -3384,7 +3385,7 @@ perft 4 535054 perft 5 14322279 perft 6 427269976 -id 1 +id 376 epd nrk1brnq/pp1p1pp1/7p/b1p1p3/1P6/6P1/P1PPPPQP/NRKBBRN1 w FBfb - 2 9 perft 1 29 perft 2 675 @@ -3393,7 +3394,7 @@ perft 4 492124 perft 5 15316285 perft 6 389051744 -id 1 +id 377 epd nrkr1bnq/1p2pppp/p2p4/1bp5/PP6/1R5N/2PPPPPP/N1KRBB1Q w Ddb - 2 9 perft 1 27 perft 2 744 @@ -3402,7 +3403,7 @@ perft 4 571209 perft 5 16188945 perft 6 458900901 -id 1 +id 378 epd nrk1b1qb/pppn1ppp/3rp3/3p4/2P3P1/3P4/PPN1PP1P/1RKRBNQB w DBb - 3 9 perft 1 35 perft 2 941 @@ -3411,7 +3412,7 @@ perft 4 935791 perft 5 33150360 perft 6 968024386 -id 1 +id 379 epd nb1rrnbq/ppkp1ppp/8/2p1p3/P7/1N2P3/1PPP1PPP/1BKRRNBQ w - - 1 9 perft 1 19 perft 2 451 @@ -3420,7 +3421,7 @@ perft 4 235472 perft 5 5506897 perft 6 139436165 -id 1 +id 380 epd nrkbrnbq/4pppp/1ppp4/p7/2P1P3/3P2N1/PP3PPP/NRKBR1BQ w EBeb - 0 9 perft 1 29 perft 2 591 @@ -3429,7 +3430,7 @@ perft 4 384358 perft 5 11245508 perft 6 270967202 -id 1 +id 381 epd nrkrnbbq/3p1ppp/1p6/p1p1p3/3P2P1/P4Q2/1PP1PP1P/NRKRNBB1 w DBdb - 0 9 perft 1 38 perft 2 792 @@ -3438,7 +3439,7 @@ perft 4 640961 perft 5 22654797 perft 6 540864616 -id 1 +id 382 epd nr1rnqbb/ppp1pp1p/3k2p1/3p4/1P5P/3P1N2/P1P1PPP1/NRKR1QBB w DB - 1 9 perft 1 25 perft 2 758 @@ -3447,7 +3448,7 @@ perft 4 543643 perft 5 13890077 perft 6 402109399 -id 1 +id 383 epd bbqrnnkr/1ppp1p1p/5p2/p5p1/P7/1P4P1/2PPPP1P/1BQRNNKR w HDhd - 0 9 perft 1 20 perft 2 322 @@ -3456,7 +3457,7 @@ perft 4 145818 perft 5 3588435 perft 6 82754650 -id 1 +id 384 epd bqrb2k1/pppppppr/5nnp/8/3P1P2/4P1N1/PPP3PP/BQRBN1KR w HCc - 1 9 perft 1 25 perft 2 597 @@ -3465,7 +3466,7 @@ perft 4 397970 perft 5 11162476 perft 6 295682250 -id 1 +id 385 epd bqrnn1kr/1pppbppp/8/4p3/1p6/2P1N2P/P2PPPP1/BQR1NBKR w HChc - 1 9 perft 1 34 perft 2 921 @@ -3474,7 +3475,7 @@ perft 4 864023 perft 5 30126510 perft 6 850296236 -id 1 +id 386 epd bqr1nkr1/pppppp2/2n3p1/7p/1P1b1P2/8/PQP1P1PP/B1RNNKRB w GCgc - 0 9 perft 1 23 perft 2 788 @@ -3483,7 +3484,7 @@ perft 4 686795 perft 5 20849374 perft 6 645694580 -id 1 +id 387 epd qbbrnn1r/1pppp1pk/p7/5p1p/P2P3P/3N4/1PP1PPP1/QBBR1NKR w HD - 0 9 perft 1 34 perft 2 713 @@ -3492,7 +3493,7 @@ perft 4 562189 perft 5 19494094 perft 6 482645160 -id 1 +id 388 epd qrbb2kr/p1pppppp/1p1n4/8/1P3n2/P7/Q1PPP1PP/1RBBNNKR w HBhb - 0 9 perft 1 28 perft 2 977 @@ -3501,7 +3502,7 @@ perft 4 949925 perft 5 27802999 perft 6 992109168 -id 1 +id 389 epd qrb2bkr/1pp1pppp/2np1n2/pN6/3P4/4B3/PPP1PPPP/QR2NBKR w HBhb - 0 9 perft 1 27 perft 2 730 @@ -3510,7 +3511,7 @@ perft 4 585091 perft 5 17005916 perft 6 507008968 -id 1 +id 390 epd qrbnnkrb/pp2pp1p/8/2pp2p1/7P/P1P5/QP1PPPP1/1RBNNKRB w GBgb - 0 9 perft 1 24 perft 2 813 @@ -3519,7 +3520,7 @@ perft 4 707925 perft 5 19615756 perft 6 655850285 -id 1 +id 391 epd 1brnb1kr/p1pppppp/1p6/8/4q2n/1P2P1P1/PNPP1P1P/QBR1BNKR w HChc - 3 9 perft 1 17 perft 2 734 @@ -3528,7 +3529,7 @@ perft 4 530809 perft 5 11032633 perft 6 416356876 -id 1 +id 392 epd 1rnbbnkr/1pp1pppp/1q1p4/p7/4P3/5PN1/PPPP1BPP/QRNB2KR w HBhb - 1 9 perft 1 26 perft 2 809 @@ -3537,7 +3538,7 @@ perft 4 706677 perft 5 20292750 perft 6 675408811 -id 1 +id 393 epd qrnnbb1Q/ppp1pk1p/3p2p1/5p2/PP6/5P2/2PPP1PP/1RNNBBKR w HB - 0 9 perft 1 37 perft 2 751 @@ -3546,7 +3547,7 @@ perft 4 603931 perft 5 22443036 perft 6 515122176 -id 1 +id 394 epd qrnnbkrb/p3p1pp/3p1p2/1pp5/PP2P3/8/2PP1PPP/QRNNBRKB w gb - 0 9 perft 1 30 perft 2 906 @@ -3555,7 +3556,7 @@ perft 4 872526 perft 5 27658191 perft 6 890966633 -id 1 +id 395 epd qbrnnkbr/1p2pp1p/p1p3p1/3p4/6P1/P1N4P/1PPPPP2/QBR1NKBR w HChc - 0 9 perft 1 26 perft 2 701 @@ -3564,7 +3565,7 @@ perft 4 521377 perft 5 14733245 perft 6 416881799 -id 1 +id 396 epd qr1b1kbr/1p1ppppp/1n1n4/p1p5/4P3/5NPP/PPPP1P2/QRNB1KBR w HBhb - 1 9 perft 1 26 perft 2 649 @@ -3573,7 +3574,7 @@ perft 4 451997 perft 5 12367604 perft 6 342165821 -id 1 +id 397 epd qrnnkb1r/1pppppp1/7p/p4b2/4P3/5P1P/PPPP2PR/QRNNKBB1 w Bhb - 1 9 perft 1 34 perft 2 941 @@ -3582,7 +3583,7 @@ perft 4 901240 perft 5 30307554 perft 6 888709821 -id 1 +id 398 epd qr1nkrbb/p2ppppp/1pp5/8/3Pn3/1NP3P1/PP2PP1P/QR1NKRBB w FBfb - 1 9 perft 1 19 perft 2 505 @@ -3591,7 +3592,7 @@ perft 4 294251 perft 5 7046501 perft 6 190414579 -id 1 +id 399 epd bbrqn1kr/1pppp1pp/4n3/5p2/p5P1/3P4/PPP1PPKP/BBRQNN1R w hc - 0 9 perft 1 24 perft 2 573 @@ -3600,7 +3601,7 @@ perft 4 335845 perft 5 8191054 perft 6 227555387 -id 1 +id 400 epd brqb1nkr/pppppp1p/8/4N1pn/5P2/6P1/PPPPP2P/BRQB1NKR w HBhb - 0 9 perft 1 26 perft 2 550 @@ -3609,7 +3610,7 @@ perft 4 331666 perft 5 8903754 perft 6 223437427 -id 1 +id 401 epd brqnn1kr/pp3ppp/2pbp3/3p4/8/2NPP3/PPP1BPPP/BRQ1N1KR w HBhb - 0 9 perft 1 27 perft 2 780 @@ -3618,7 +3619,7 @@ perft 4 589328 perft 5 16243731 perft 6 463883447 -id 1 +id 402 epd brq1nkrb/ppp2ppp/8/n2pp2P/P7/4P3/1PPP1PP1/BRQNNKRB w GBgb - 1 9 perft 1 17 perft 2 426 @@ -3627,7 +3628,7 @@ perft 4 235162 perft 5 5048497 perft 6 153986034 -id 1 +id 403 epd rbbqn1kr/pp2p1pp/6n1/2pp1p2/2P4P/P7/BP1PPPP1/R1BQNNKR w HAha - 0 9 perft 1 27 perft 2 916 @@ -3636,7 +3637,7 @@ perft 4 890435 perft 5 26302461 perft 6 924181432 -id 1 +id 404 epd 1qbbn1kr/1ppppppp/r3n3/8/p1P5/P7/1P1PPPPP/RQBBNNKR w HAh - 1 9 perft 1 29 perft 2 817 @@ -3645,7 +3646,7 @@ perft 4 720277 perft 5 22147642 perft 6 670707652 -id 1 +id 405 epd rqbnnbkr/ppp1ppp1/7p/3p4/PP6/7P/1NPPPPP1/RQB1NBKR w HAa - 1 9 perft 1 23 perft 2 572 @@ -3654,7 +3655,7 @@ perft 4 381474 perft 5 10416981 perft 6 288064942 -id 1 +id 406 epd r1bnnkrb/q1ppp1pp/p7/1p3pB1/2P1P3/3P4/PP3PPP/RQ1NNKRB w GAga - 2 9 perft 1 31 perft 2 925 @@ -3663,7 +3664,7 @@ perft 4 860969 perft 5 26316355 perft 6 843078864 -id 1 +id 407 epd rbqnb1kr/ppppp1pp/5p2/5N2/7P/1n3P2/PPPPP1P1/RBQNB1KR w HAha - 1 9 perft 1 32 perft 2 864 @@ -3672,7 +3673,7 @@ perft 4 766551 perft 5 24738875 perft 6 707188107 -id 1 +id 408 epd rqnbbn1r/ppppppp1/6k1/8/6Pp/2PN4/PP1PPPKP/RQ1BBN1R w - - 0 9 perft 1 27 perft 2 566 @@ -3681,7 +3682,7 @@ perft 4 347059 perft 5 9714509 perft 6 234622128 -id 1 +id 409 epd rqnnbbkr/p1p2pp1/1p1p3p/4p3/4NP2/6P1/PPPPP2P/RQN1BBKR w HAha - 0 9 perft 1 27 perft 2 631 @@ -3690,7 +3691,7 @@ perft 4 452734 perft 5 13307890 perft 6 356279813 -id 1 +id 410 epd 1qnnbrkb/rppp1ppp/p3p3/8/4P3/2PP1P2/PP4PP/RQNNBKRB w GA - 1 9 perft 1 24 perft 2 479 @@ -3699,7 +3700,7 @@ perft 4 271469 perft 5 7204345 perft 6 175460841 -id 1 +id 411 epd rbqnn1br/p1pppk1p/1p4p1/5p2/8/P1P2P2/1PBPP1PP/R1QNNKBR w HA - 0 9 perft 1 31 perft 2 756 @@ -3708,7 +3709,7 @@ perft 4 625194 perft 5 20036784 perft 6 554292502 -id 1 +id 412 epd rqnbnkbr/1ppppp2/p5p1/8/1P4p1/4PP2/P1PP3P/RQNBNKBR w HAha - 0 9 perft 1 24 perft 2 715 @@ -3717,7 +3718,7 @@ perft 4 575589 perft 5 16013189 perft 6 515078271 -id 1 +id 413 epd rq1nkbbr/1p2pppp/p2n4/2pp4/1P4P1/P2N4/2PPPP1P/RQ1NKBBR w HAha - 1 9 perft 1 27 perft 2 694 @@ -3726,7 +3727,7 @@ perft 4 552904 perft 5 16685687 perft 6 494574415 -id 1 +id 414 epd r1nnkrbb/pp1pppp1/2p3q1/7p/8/1PPP3P/P3PPP1/RQNNKRBB w FAfa - 1 9 perft 1 18 perft 2 520 @@ -3735,7 +3736,7 @@ perft 4 329085 perft 5 7508201 perft 6 235103697 -id 1 +id 415 epd bbrnqk1r/pppp3p/6p1/4pp2/3P2P1/8/PPP1PP1P/BBRN1NKR w HC - 0 9 perft 1 22 perft 2 566 @@ -3744,7 +3745,7 @@ perft 4 362624 perft 5 8721079 perft 6 259069471 -id 1 +id 416 epd brnb1nkr/pppqpp2/3p2pp/8/3PP3/1P6/PBP2PPP/1RNBQNKR w HBhb - 0 9 perft 1 32 perft 2 859 @@ -3753,7 +3754,7 @@ perft 4 817464 perft 5 27734108 perft 6 829785474 -id 1 +id 417 epd brnq1b1r/ppp1ppkp/3p1np1/8/8/5P1P/PPPPPKPR/BRNQNB2 w - - 0 9 perft 1 21 perft 2 511 @@ -3762,7 +3763,7 @@ perft 4 273756 perft 5 6372681 perft 6 167139732 -id 1 +id 418 epd brnq1rkb/1pppppp1/3n3p/p7/8/P4NP1/1PPPPPRP/BRNQ1K1B w B - 0 9 perft 1 25 perft 2 548 @@ -3771,7 +3772,7 @@ perft 4 341208 perft 5 9015901 perft 6 235249649 -id 1 +id 419 epd rbb1qnkr/p1ppp1pp/1p3p2/6n1/8/1PN1P2P/P1PP1PP1/RBB1QNKR w HAha - 0 9 perft 1 25 perft 2 673 @@ -3780,7 +3781,7 @@ perft 4 467660 perft 5 12099119 perft 6 361714466 -id 1 +id 420 epd rnbb1nkr/1ppp1ppp/4p3/p5q1/6P1/1PP5/PB1PPP1P/RN1BQNKR w HAha - 1 9 perft 1 19 perft 2 663 @@ -3789,7 +3790,7 @@ perft 4 489653 perft 5 11491355 perft 6 399135495 -id 1 +id 421 epd rnbqnbkr/1pp1p2p/3p1p2/p5p1/5PP1/2P5/PPNPP2P/RNBQ1BKR w HAha - 0 9 perft 1 24 perft 2 647 @@ -3798,7 +3799,7 @@ perft 4 461931 perft 5 12649636 perft 6 361157611 -id 1 +id 422 epd rnb2krb/pppqppnp/8/3p2p1/1P4P1/7P/P1PPPPB1/RNBQNKR1 w GAga - 1 9 perft 1 24 perft 2 722 @@ -3807,7 +3808,7 @@ perft 4 605229 perft 5 16609220 perft 6 563558512 -id 1 +id 423 epd rbnqb1kr/pppn1pp1/3p3p/4p3/1P6/P7/R1PPPPPP/1BNQBNKR w Hha - 1 9 perft 1 20 perft 2 538 @@ -3816,7 +3817,7 @@ perft 4 345704 perft 5 8687621 perft 6 255304141 -id 1 +id 424 epd rnqb1nkr/p1pbp1pp/8/1pPp1p2/P2P4/8/1P2PPPP/RNQBBNKR w HAha - 1 9 perft 1 35 perft 2 764 @@ -3825,7 +3826,7 @@ perft 4 632796 perft 5 22592380 perft 6 564255328 -id 1 +id 425 epd rnq1bbkr/1p1ppp1p/4n3/p1p3p1/P1PP4/8/RP2PPPP/1NQNBBKR w Hha - 0 9 perft 1 29 perft 2 709 @@ -3834,7 +3835,7 @@ perft 4 570580 perft 5 17597398 perft 6 506140370 -id 1 +id 426 epd 1nqnbkrb/1pppp2p/r7/p4pp1/3P4/8/PPPBPPPP/RNQNK1RB w g - 0 9 perft 1 27 perft 2 1028 @@ -3843,7 +3844,7 @@ perft 4 1050834 perft 5 30251988 perft 6 1096869832 -id 1 +id 427 epd rbnqnkbr/p1pp1p1p/8/1p2p3/3P2pP/2P5/PP2PPP1/RBNQNKBR w HAha - 0 9 perft 1 32 perft 2 832 @@ -3852,7 +3853,7 @@ perft 4 750336 perft 5 24945574 perft 6 724171581 -id 1 +id 428 epd rnq1nkbr/1p1p1ppp/2p1pb2/p7/7P/2P5/PPNPPPPB/RNQB1K1R w HAha - 2 9 perft 1 31 perft 2 779 @@ -3861,7 +3862,7 @@ perft 4 638640 perft 5 19919434 perft 6 551494771 -id 1 +id 429 epd rnqnk1br/p1ppp1bp/1p3p2/6p1/4N3/P5P1/1PPPPP1P/R1QNKBBR w HAha - 2 9 perft 1 25 perft 2 717 @@ -3870,7 +3871,7 @@ perft 4 576577 perft 5 16525239 perft 6 507175842 -id 1 +id 430 epd rnq1krbb/p1p1pppp/8/1p1p4/1n5B/2N2P2/PPPPP1PP/RNQ1KR1B w FAfa - 0 9 perft 1 28 perft 2 867 @@ -3879,7 +3880,7 @@ perft 4 735686 perft 5 21112751 perft 6 654808184 -id 1 +id 431 epd bbrnnqkr/1pp1pppp/3p4/p7/P3P3/7P/1PPP1PP1/BBRNNQKR w HChc - 0 9 perft 1 24 perft 2 405 @@ -3888,7 +3889,7 @@ perft 4 210557 perft 5 6196438 perft 6 131401224 -id 1 +id 432 epd brnbnqkr/p1ppp3/1p5p/5Pp1/5P2/3N4/PPPPP2P/BRNB1QKR w HBhb g6 0 9 perft 1 25 perft 2 785 @@ -3897,7 +3898,7 @@ perft 4 698331 perft 5 20687969 perft 6 695850727 -id 1 +id 433 epd br1nqbkr/1ppppp2/pn6/6pp/2PP4/1N4P1/PP2PP1P/BR1NQBKR w HBhb - 0 9 perft 1 25 perft 2 596 @@ -3906,7 +3907,7 @@ perft 4 421882 perft 5 12185361 perft 6 337805606 -id 1 +id 434 epd 1rnnqkrb/p2ppp1p/1pp5/2N3p1/8/1P6/P1PPPPKP/BR1NQ1RB w gb - 0 9 perft 1 38 perft 2 960 @@ -3915,7 +3916,7 @@ perft 4 913665 perft 5 32490040 perft 6 880403591 -id 1 +id 435 epd rbbnnqkr/pp3pp1/2p1p3/3p3p/3P3P/1PP5/P3PPP1/RBBNNQKR w HAha - 0 9 perft 1 30 perft 2 785 @@ -3924,7 +3925,7 @@ perft 4 656618 perft 5 19885037 perft 6 599219582 -id 1 +id 436 epd rn1bnqkr/p1ppppp1/8/1p5p/P4P1P/3N4/1PPPP1b1/RNBB1QKR w HAha - 0 9 perft 1 27 perft 2 752 @@ -3933,7 +3934,7 @@ perft 4 613194 perft 5 18862234 perft 6 547415271 -id 1 +id 437 epd 1nbnqbkr/1p1p1ppp/r3p3/p1p5/P3P3/3Q4/1PPP1PPP/RNBN1BKR w HAh - 2 9 perft 1 33 perft 2 721 @@ -3942,7 +3943,7 @@ perft 4 572535 perft 5 19648535 perft 6 496023732 -id 1 +id 438 epd rnbnqkrb/2pppppp/1p6/p7/1PP5/4N2P/P2PPPP1/RNB1QKRB w GAg - 0 9 perft 1 23 perft 2 570 @@ -3951,7 +3952,7 @@ perft 4 374196 perft 5 10022614 perft 6 279545007 -id 1 +id 439 epd rbnnbq1r/ppppppkp/6p1/N7/4P3/P7/1PPP1PPP/RB1NBQKR w HA - 5 9 perft 1 27 perft 2 620 @@ -3960,7 +3961,7 @@ perft 4 440594 perft 5 13909432 perft 6 349478320 -id 1 +id 440 epd r1nbbqkr/pppppp1p/8/8/1n3Pp1/3N1QP1/PPPPP2P/RN1BB1KR w HAha - 0 9 perft 1 31 perft 2 791 @@ -3969,7 +3970,7 @@ perft 4 682579 perft 5 22408813 perft 6 636779732 -id 1 +id 441 epd rnq1bbkr/pp1p1ppp/2pnp3/8/7P/1QP5/PP1PPPPR/RNN1BBK1 w Aha - 2 9 perft 1 28 perft 2 559 @@ -3978,7 +3979,7 @@ perft 4 390887 perft 5 12242780 perft 6 315431511 -id 1 +id 442 epd rnnqbrkb/2ppppp1/1p1N4/p6p/4P3/8/PPPP1PPP/R1NQBKRB w GA - 0 9 perft 1 32 perft 2 638 @@ -3987,7 +3988,7 @@ perft 4 438792 perft 5 14395828 perft 6 331782223 -id 1 +id 443 epd rbnnq1br/pppp1kp1/4pp2/7p/PP6/2PP4/4PPPP/RBNNQKBR w HA - 0 9 perft 1 21 perft 2 521 @@ -3996,7 +3997,7 @@ perft 4 320429 perft 5 8239159 perft 6 227346638 -id 1 +id 444 epd rnnbqkbr/p2ppp2/7p/1pp3p1/2P2N2/8/PP1PPPPP/RN1BQKBR w HAha - 0 9 perft 1 25 perft 2 528 @@ -4005,7 +4006,7 @@ perft 4 326094 perft 5 9079829 perft 6 232750602 -id 1 +id 445 epd rnn1kbbr/ppppqp2/6p1/2N1p2p/P7/2P5/1P1PPPPP/RN1QKBBR w HAha - 2 9 perft 1 27 perft 2 801 @@ -4014,7 +4015,7 @@ perft 4 707078 perft 5 20334071 perft 6 682580976 -id 1 +id 446 epd rnnqkrbb/p1p1p1pp/1p3p2/8/3p2Q1/P1P1P3/1P1P1PPP/RNN1KRBB w FAfa - 0 9 perft 1 37 perft 2 1014 @@ -4023,7 +4024,7 @@ perft 4 998999 perft 5 32921537 perft 6 988770109 -id 1 +id 447 epd bbrnk1qr/1pppppp1/p4n1p/8/P2P2N1/8/1PP1PPPP/BBR1NKQR w HC - 1 9 perft 1 21 perft 2 481 @@ -4032,7 +4033,7 @@ perft 4 279993 perft 5 7015419 perft 6 187564853 -id 1 +id 448 epd brnbnkqr/1pp1p1p1/p2p1p2/7p/1P4PP/8/PBPPPP2/1RNBNKQR w HBhb - 0 9 perft 1 31 perft 2 743 @@ -4041,7 +4042,7 @@ perft 4 660177 perft 5 22391185 perft 6 653721389 -id 1 +id 449 epd br2kbqr/ppppp1pp/3n1p2/3P4/3n3P/3N4/PPP1PPP1/BR1NKBQR w HBhb - 3 9 perft 1 25 perft 2 872 @@ -4050,7 +4051,7 @@ perft 4 748726 perft 5 20281962 perft 6 685749952 -id 1 +id 450 epd br1nkqrb/ppppppp1/8/7p/4P3/n1P2PP1/PP1P3P/BRNNKQRB w GBgb - 0 9 perft 1 28 perft 2 607 @@ -4059,7 +4060,7 @@ perft 4 396483 perft 5 11607818 perft 6 294181806 -id 1 +id 451 epd rbbn1kqr/pp1pp1p1/2pn3p/5p2/5P2/1P1N4/PNPPP1PP/RBB2KQR w HAha - 1 9 perft 1 27 perft 2 725 @@ -4068,7 +4069,7 @@ perft 4 616082 perft 5 19239812 perft 6 581716972 -id 1 +id 452 epd rnbbnk1r/pp1ppp1p/6q1/2p5/PP4p1/4P3/2PP1PPP/RNBBNKQR w HAha - 1 9 perft 1 25 perft 2 1072 @@ -4077,7 +4078,7 @@ perft 4 1088978 perft 5 28469879 perft 6 1122703887 -id 1 +id 453 epd rnbnkbqr/1pp3pp/3p4/p3pp2/3P2P1/2N1N3/PPP1PP1P/R1B1KBQR w HAha - 0 9 perft 1 31 perft 2 1028 @@ -4086,7 +4087,7 @@ perft 4 1095472 perft 5 36025223 perft 6 1211187800 -id 1 +id 454 epd r1bnkqrb/1ppppppp/p3n3/8/6P1/4N3/PPPPPPRP/RNB1KQ1B w Aga - 1 9 perft 1 23 perft 2 457 @@ -4095,7 +4096,7 @@ perft 4 250551 perft 5 6666787 perft 6 159759052 -id 1 +id 455 epd rbn1bkqr/p1pp1pp1/1pn5/4p2p/7P/1PBP4/P1P1PPP1/RBNN1KQR w HAha - 0 9 perft 1 23 perft 2 470 @@ -4104,7 +4105,7 @@ perft 4 264274 perft 5 6963287 perft 6 172833738 -id 1 +id 456 epd rnnbbkqr/3ppppp/p7/1pp5/P6P/6P1/1PPPPP2/RNNBBKQR w HAha - 0 9 perft 1 26 perft 2 569 @@ -4113,7 +4114,7 @@ perft 4 375556 perft 5 11008114 perft 6 284485303 -id 1 +id 457 epd r1nk1bqr/1pppp1pp/2n5/p4p1b/5P2/1N4B1/PPPPP1PP/RN1K1BQR w HAha - 2 9 perft 1 25 perft 2 824 @@ -4122,7 +4123,7 @@ perft 4 738366 perft 5 20904119 perft 6 716170771 -id 1 +id 458 epd r1nkbqrb/p2pppp1/npp4p/8/4PP2/2N4P/PPPP2P1/R1NKBQRB w GAga - 0 9 perft 1 31 perft 2 548 @@ -4131,7 +4132,7 @@ perft 4 349633 perft 5 11469548 perft 6 255067638 -id 1 +id 459 epd rbnnkqbr/ppppp2p/5p2/6p1/2P1B3/P6P/1P1PPPP1/R1NNKQBR w HAha - 1 9 perft 1 31 perft 2 809 @@ -4140,7 +4141,7 @@ perft 4 680747 perft 5 21247414 perft 6 606221516 -id 1 +id 460 epd 1r1bkqbr/pppp1ppp/2nnp3/8/2P5/N4P2/PP1PP1PP/1RNBKQBR w Hh - 0 9 perft 1 28 perft 2 810 @@ -4149,7 +4150,7 @@ perft 4 694599 perft 5 20188622 perft 6 636748147 -id 1 +id 461 epd rn1kqbbr/p1pppp1p/1p4p1/1n6/1P2P3/4Q2P/P1PP1PP1/RNNK1BBR w HAha - 1 9 perft 1 39 perft 2 848 @@ -4158,7 +4159,7 @@ perft 4 724426 perft 5 25594662 perft 6 659615710 -id 1 +id 462 epd rn1kqrbb/pppppppp/8/8/2nP2P1/1P2P3/P1P2P1P/RNNKQRBB w FAfa - 1 9 perft 1 29 perft 2 766 @@ -4167,7 +4168,7 @@ perft 4 567971 perft 5 16944425 perft 6 456898648 -id 1 +id 463 epd b1rnnkrq/bpppppp1/7p/8/1p6/2B5/PNPPPPPP/1BR1NKRQ w GCgc - 2 9 perft 1 25 perft 2 667 @@ -4176,7 +4177,7 @@ perft 4 472678 perft 5 12865247 perft 6 365621294 -id 1 +id 464 epd brnb1krq/pppppppp/8/5P2/2P1n2P/8/PP1PP1P1/BRNBNKRQ w GBgb - 1 9 perft 1 23 perft 2 620 @@ -4185,7 +4186,7 @@ perft 4 402561 perft 5 10776855 perft 6 300125003 -id 1 +id 465 epd b1nnkbrq/pr1pppp1/1p5p/2p5/P2N1P2/8/1PPPP1PP/BR1NKBRQ w GBg - 0 9 perft 1 24 perft 2 472 @@ -4194,7 +4195,7 @@ perft 4 267398 perft 5 7370758 perft 6 178605165 -id 1 +id 466 epd br1nkrqb/p1p1p1pp/3n4/1p1p1p2/5N1P/4P3/PPPP1PP1/BR1NKRQB w FBfb - 0 9 perft 1 24 perft 2 775 @@ -4203,7 +4204,7 @@ perft 4 624309 perft 5 16429837 perft 6 539767605 -id 1 +id 467 epd rbbnnkrq/p2pp1pp/2p5/5p2/1pPP1B2/P7/1P2PPPP/RB1NNKRQ w GAga - 0 9 perft 1 34 perft 2 921 @@ -4212,7 +4213,7 @@ perft 4 849933 perft 5 28095833 perft 6 806446436 -id 1 +id 468 epd rnbbnkr1/1p1ppp1p/2p3p1/p7/2Pq4/1P1P4/P2BPPPP/RN1BNKRQ w GAga - 2 9 perft 1 26 perft 2 1139 @@ -4221,7 +4222,7 @@ perft 4 1204863 perft 5 32825932 perft 6 1281760240 -id 1 +id 469 epd 1rbnkbrq/pppppp2/n5pp/2P5/P7/4N3/1P1PPPPP/RNB1KBRQ w GAg - 2 9 perft 1 23 perft 2 574 @@ -4230,7 +4231,7 @@ perft 4 391413 perft 5 10203438 perft 6 301874034 -id 1 +id 470 epd 1nbnkr1b/rppppppq/p7/7p/1P5P/3P2P1/P1P1PP2/RNBNKRQB w FAf - 1 9 perft 1 33 perft 2 823 @@ -4239,7 +4240,7 @@ perft 4 724828 perft 5 23266182 perft 6 672294132 -id 1 +id 471 epd rbn1bkrq/ppppp3/4n2p/5pp1/1PN5/2P5/P2PPPPP/RBN1BKRQ w GAga - 0 9 perft 1 27 perft 2 859 @@ -4248,7 +4249,7 @@ perft 4 796482 perft 5 23075785 perft 6 789152120 -id 1 +id 472 epd r1nbbkrq/1ppp2pp/2n2p2/p3p3/5P2/1N4BP/PPPPP1P1/RN1B1KRQ w GAga - 0 9 perft 1 25 perft 2 774 @@ -4257,7 +4258,7 @@ perft 4 618805 perft 5 16718577 perft 6 515864053 -id 1 +id 473 epd rnnkbbrq/1pppp1p1/5p2/7p/p6P/3N1P2/PPPPP1PQ/RN1KBBR1 w GAga - 0 9 perft 1 29 perft 2 673 @@ -4266,7 +4267,7 @@ perft 4 504715 perft 5 15545590 perft 6 416359581 -id 1 +id 474 epd r1nkbrqb/pppp1p2/n3p1p1/7p/2P2P2/1P6/P2PPQPP/RNNKBR1B w FAfa - 0 9 perft 1 27 perft 2 722 @@ -4275,7 +4276,7 @@ perft 4 593762 perft 5 18742426 perft 6 537750982 -id 1 +id 475 epd rbnnkr1q/1ppp2pp/p4p2/P2bp3/4P2P/8/1PPP1PP1/RBNNKRBQ w FAfa - 1 9 perft 1 26 perft 2 848 @@ -4284,7 +4285,7 @@ perft 4 741674 perft 5 21591790 perft 6 675163653 -id 1 +id 476 epd rn1bkrb1/1ppppp1p/pn4p1/8/P2q3P/3P4/NPP1PPP1/RN1BKRBQ w FAfa - 1 9 perft 1 22 perft 2 803 @@ -4293,7 +4294,7 @@ perft 4 632920 perft 5 15847763 perft 6 536419559 -id 1 +id 477 epd rn1krbbq/pppp1npp/4pp2/8/4P2P/3P2P1/PPP2P2/RNNKRBBQ w EAea - 1 9 perft 1 29 perft 2 810 @@ -4302,7 +4303,7 @@ perft 4 670500 perft 5 20361517 perft 6 575069358 -id 1 +id 478 epd rnn1rqbb/ppkp1pp1/2p1p2p/2P5/8/3P1P2/PP2P1PP/RNNKRQBB w EA - 0 9 perft 1 22 perft 2 506 @@ -4311,7 +4312,7 @@ perft 4 292344 perft 5 7287368 perft 6 189865944 -id 1 +id 479 epd bbqr1knr/pppppp1p/8/4n1p1/2P1P3/6P1/PPQP1P1P/BB1RNKNR w HDhd - 0 9 perft 1 26 perft 2 650 @@ -4320,7 +4321,7 @@ perft 4 481200 perft 5 14301029 perft 6 394943978 -id 1 +id 480 epd bq1bnknr/pprppp1p/8/2p3p1/4PPP1/8/PPPP3P/BQRBNKNR w HCh - 0 9 perft 1 24 perft 2 548 @@ -4329,7 +4330,7 @@ perft 4 347611 perft 5 9374021 perft 6 250988458 -id 1 +id 481 epd bqrnkb1r/1p2pppp/p1pp3n/5Q2/2P4P/5N2/PP1PPPP1/B1RNKB1R w HChc - 0 9 perft 1 46 perft 2 823 @@ -4338,7 +4339,7 @@ perft 4 673905 perft 5 26130444 perft 6 582880996 -id 1 +id 482 epd bq1rknrb/pppppp1p/4n3/6p1/4P1P1/3P1P2/PPP4P/BQRNKNRB w GCg - 0 9 perft 1 23 perft 2 618 @@ -4347,7 +4348,7 @@ perft 4 419474 perft 5 10606831 perft 6 315124518 -id 1 +id 483 epd q1brnknr/pp1pp1p1/8/2p2p1p/5b2/P4N2/1PPPP1PP/QBBRK1NR w hd - 0 9 perft 1 22 perft 2 675 @@ -4356,7 +4357,7 @@ perft 4 473994 perft 5 12077228 perft 6 368479752 -id 1 +id 484 epd qrbbnknr/1p1ppp1p/p1p5/8/1P2P1p1/3P1B2/P1P2PPP/QRB1NKNR w HBhb - 0 9 perft 1 32 perft 2 722 @@ -4365,7 +4366,7 @@ perft 4 569905 perft 5 19584539 perft 6 484814878 -id 1 +id 485 epd qrb1kbnr/p3pppp/2n5/1ppp4/7P/3P1P2/PPP1P1PR/QRBNKBN1 w Bhb - 0 9 perft 1 26 perft 2 831 @@ -4374,7 +4375,7 @@ perft 4 724505 perft 5 20500804 perft 6 662608969 -id 1 +id 486 epd qrbnknrb/ppp1pp2/6p1/7p/PPNp4/8/2PPPPPP/QRB1KNRB w GBgb - 0 9 perft 1 31 perft 2 840 @@ -4383,7 +4384,7 @@ perft 4 742772 perft 5 24422614 perft 6 701363800 -id 1 +id 487 epd qbrnbknr/pp1pp1pp/8/2p2p2/3Q4/PP6/2PPPPPP/1BRNBKNR w HChc - 0 9 perft 1 38 perft 2 1121 @@ -4392,7 +4393,7 @@ perft 4 1198438 perft 5 41108769 perft 6 1285503872 -id 1 +id 488 epd qr1bbk1r/pppppp1p/1n6/5np1/4B3/1PP5/P2PPPPP/QRN1BKNR w HBhb - 0 9 perft 1 25 perft 2 694 @@ -4401,7 +4402,7 @@ perft 4 472950 perft 5 12164609 perft 6 345122090 -id 1 +id 489 epd qrnkbbnr/1p1pp2p/p7/2p1Npp1/6P1/7P/PPPPPP2/QR1KBBNR w HBhb - 0 9 perft 1 27 perft 2 586 @@ -4410,7 +4411,7 @@ perft 4 393391 perft 5 11409633 perft 6 298054792 -id 1 +id 490 epd qrnkbnrb/pp1p1p2/2p1p1pp/4N3/P4P2/8/1PPPP1PP/QR1KBNRB w GBgb - 0 9 perft 1 32 perft 2 645 @@ -4419,7 +4420,7 @@ perft 4 460319 perft 5 15037464 perft 6 358531599 -id 1 +id 491 epd qbrnknbr/1pppppp1/p6p/8/1P6/3PP3/PQP2PPP/1BRNKNBR w HChc - 3 9 perft 1 26 perft 2 595 @@ -4428,7 +4429,7 @@ perft 4 415022 perft 5 12214768 perft 6 323518628 -id 1 +id 492 epd qrnbk1br/1ppppp1p/p5p1/8/4Pn2/4K1P1/PPPP1P1P/QRNB1NBR w hb - 0 9 perft 1 24 perft 2 609 @@ -4437,7 +4438,7 @@ perft 4 359415 perft 5 8538539 perft 6 230364479 -id 1 +id 493 epd qrnk1bbr/1pnp1ppp/p1p1p3/8/3Q4/1P1N3P/P1PPPPP1/1RNK1BBR w HBhb - 0 9 perft 1 43 perft 2 1106 @@ -4446,7 +4447,7 @@ perft 4 1123080 perft 5 41695761 perft 6 1113836402 -id 1 +id 494 epd qrnknrb1/pppppp2/8/6pp/4P2P/3P1P2/PbP3P1/QRNKNRBB w FBfb - 0 9 perft 1 24 perft 2 658 @@ -4455,7 +4456,7 @@ perft 4 488373 perft 5 14457245 perft 6 400971226 -id 1 +id 495 epd bbrqnrk1/ppp2ppp/7n/3pp3/8/P4N1N/1PPPPPPP/BBRQ1RK1 w - - 1 9 perft 1 22 perft 2 503 @@ -4464,7 +4465,7 @@ perft 4 310760 perft 5 8080951 perft 6 224960353 -id 1 +id 496 epd brqbnk1r/1ppp1ppp/8/p3pn2/8/2PP1P2/PP2PKPP/BRQBN1NR w hb - 1 9 perft 1 25 perft 2 745 @@ -4473,7 +4474,7 @@ perft 4 570459 perft 5 15520298 perft 6 460840861 -id 1 +id 497 epd brqnkbnr/pp2pp1p/3p4/2p5/5p2/3P3P/PPP1PPP1/B1RNKBNR w Hhb - 0 9 perft 1 19 perft 2 516 @@ -4482,7 +4483,7 @@ perft 4 312996 perft 5 6995034 perft 6 214340699 -id 1 +id 498 epd brq1kn1b/1ppppprp/2n3p1/p7/P1N5/6P1/1PPPPP1P/BRQNK1RB w GBb - 2 9 perft 1 29 perft 2 557 @@ -4491,7 +4492,7 @@ perft 4 352277 perft 5 10840256 perft 6 249999654 -id 1 +id 499 epd rbbq1k1r/ppp1pppp/7n/1n1p4/5P2/P2P4/1PPBP1PP/RB1QNKNR w HAha - 1 9 perft 1 25 perft 2 769 @@ -4500,7 +4501,7 @@ perft 4 638340 perft 5 17438715 perft 6 570893953 -id 1 +id 500 epd r1bbnk1r/qpp1pppp/p6n/3p4/1P6/5N1P/P1PPPPP1/RQBBK1NR w ha - 0 9 perft 1 23 perft 2 728 @@ -4509,7 +4510,7 @@ perft 4 587364 perft 5 16053564 perft 6 529082811 -id 1 +id 501 epd rqbnkbnr/1pp2p1p/3p4/p3p1p1/8/2P2P2/PP1PPNPP/RQBNKB1R w HAha - 0 9 perft 1 26 perft 2 772 @@ -4518,7 +4519,7 @@ perft 4 653704 perft 5 19571559 perft 6 593915677 -id 1 +id 502 epd r1bnknrb/pqppp1p1/1p5p/5p2/7P/3P2N1/PPP1PPP1/RQBNK1RB w GAga - 2 9 perft 1 27 perft 2 748 @@ -4527,7 +4528,7 @@ perft 4 597105 perft 5 16324542 perft 6 506453626 -id 1 +id 503 epd rbqnbknr/pp1pppp1/8/2p5/3P3p/5N1P/PPP1PPPR/RBQNBK2 w Aha - 0 9 perft 1 30 perft 2 859 @@ -4536,7 +4537,7 @@ perft 4 819631 perft 5 26363334 perft 6 842796987 -id 1 +id 504 epd rqnbbrk1/ppppppp1/8/5n1p/3P3P/2B3P1/PPP1PP2/RQNB1KNR w HA - 0 9 perft 1 22 perft 2 505 @@ -4545,7 +4546,7 @@ perft 4 283464 perft 5 7055215 perft 6 186760784 -id 1 +id 505 epd rqnkbbnr/pp2p1p1/8/2pp1p1p/3PPP2/8/PPP1N1PP/RQNKBB1R w HAha - 0 9 perft 1 28 perft 2 832 @@ -4554,7 +4555,7 @@ perft 4 722857 perft 5 20429246 perft 6 663183060 -id 1 +id 506 epd rqnkbnr1/pppp2bp/6p1/4pp2/1P2P3/3NN3/P1PP1PPP/RQ1KB1RB w GAga - 0 9 perft 1 28 perft 2 641 @@ -4563,7 +4564,7 @@ perft 4 459993 perft 5 14038570 perft 6 364210162 -id 1 +id 507 epd rbq2kbr/pppppppp/2n5/P7/3P1n2/2P5/1P2PPPP/RBQNKNBR w HA - 1 9 perft 1 31 perft 2 889 @@ -4572,7 +4573,7 @@ perft 4 766181 perft 5 24299415 perft 6 692180754 -id 1 +id 508 epd rq1bkn1r/ppppp2p/3n4/5pp1/2b3P1/1N1P1P2/PPP1P2P/RQ1BKNBR w HAha - 1 9 perft 1 28 perft 2 810 @@ -4581,7 +4582,7 @@ perft 4 657520 perft 5 18719949 perft 6 556282676 -id 1 +id 509 epd r1nknbbr/p2ppp1p/1pp3p1/8/1P6/4P3/P1PPNPPq/R1QKNBBR w HAha - 0 9 perft 1 24 perft 2 797 @@ -4590,7 +4591,7 @@ perft 4 719069 perft 5 21862776 perft 6 716521139 -id 1 +id 510 epd rqnknrbb/ppp1p3/5ppp/2Np4/2P5/4P3/PP1P1PPP/RQNK1RBB w FAfa - 0 9 perft 1 34 perft 2 686 @@ -4599,7 +4600,7 @@ perft 4 515541 perft 5 17664543 perft 6 423574794 -id 1 +id 511 epd 1brnqknr/2p1pppp/p2p4/1P6/6P1/4Nb2/PP1PPP1P/BBR1QKNR w HChc - 1 9 perft 1 34 perft 2 1019 @@ -4608,7 +4609,7 @@ perft 4 1003103 perft 5 33322477 perft 6 1043293394 -id 1 +id 512 epd brn1qknr/1p1pppp1/pb5p/Q1p5/3P3P/8/PPP1PPPR/BRNB1KN1 w Bhb - 2 9 perft 1 32 perft 2 642 @@ -4617,7 +4618,7 @@ perft 4 464895 perft 5 15454749 perft 6 371861782 -id 1 +id 513 epd brnqkbnr/pppppp2/8/6pp/6P1/P2P1P2/1PP1P2P/BRNQKBNR w HBhb - 0 9 perft 1 20 perft 2 441 @@ -4626,7 +4627,7 @@ perft 4 240220 perft 5 5770284 perft 6 153051835 -id 1 +id 514 epd 2nqknrb/1rpppppp/5B2/pp6/1PP1b3/3P4/P3PPPP/1RNQKNRB w GBg - 1 9 perft 1 35 perft 2 1042 @@ -4635,7 +4636,7 @@ perft 4 1101159 perft 5 38505058 perft 6 1202668717 -id 1 +id 515 epd rb1nqknr/1pp1pppp/8/3p4/p2P4/6PN/PPPQPP1P/RBBN1K1R w HAha - 0 9 perft 1 29 perft 2 692 @@ -4644,7 +4645,7 @@ perft 4 555018 perft 5 17820605 perft 6 497251206 -id 1 +id 516 epd rnbbqknr/pppp4/5p2/4p1pp/P7/2N2PP1/1PPPP2P/R1BBQKNR w HAha - 0 9 perft 1 23 perft 2 595 @@ -4653,7 +4654,7 @@ perft 4 415772 perft 5 10881112 perft 6 329010121 -id 1 +id 517 epd rn1qkbnr/p1p1pp1p/bp4p1/3p4/1P6/4P3/P1PP1PPP/RNBQKBNR w HAha - 0 9 perft 1 30 perft 2 794 @@ -4662,7 +4663,7 @@ perft 4 690811 perft 5 21657601 perft 6 647745807 -id 1 +id 518 epd r1bqk1rb/pppnpppp/5n2/3p4/2P3PP/2N5/PP1PPP2/R1BQKNRB w GAga - 1 9 perft 1 32 perft 2 821 @@ -4671,7 +4672,7 @@ perft 4 733155 perft 5 24923473 perft 6 710765657 -id 1 +id 519 epd rbnqbknr/1p1ppp1p/6p1/p1p5/7P/3P4/PPP1PPP1/RBNQBKNR w HAha - 0 9 perft 1 24 perft 2 720 @@ -4680,7 +4681,7 @@ perft 4 575027 perft 5 15992882 perft 6 501093456 -id 1 +id 520 epd r1qbbk1r/pp1ppppp/n1p5/5n2/B1P3P1/8/PP1PPP1P/RNQ1BKNR w HAha - 0 9 perft 1 27 perft 2 831 @@ -4689,7 +4690,7 @@ perft 4 698986 perft 5 19948650 perft 6 637973209 -id 1 +id 521 epd rnqkbb1r/p1pppppp/8/8/1p4n1/PP4PP/2PPPP2/RNQKBBNR w HAha - 0 9 perft 1 18 perft 2 463 @@ -4698,7 +4699,7 @@ perft 4 256152 perft 5 6065231 perft 6 172734380 -id 1 +id 522 epd rnqk1nrb/pppbpp2/7p/3p2p1/4B3/2N1N1P1/PPPPPP1P/R1QKB1R1 w GAga - 0 9 perft 1 34 perft 2 1171 @@ -4707,7 +4708,7 @@ perft 4 1318217 perft 5 42109356 perft 6 1465473753 -id 1 +id 523 epd rbnqknbr/1pp1ppp1/3p4/7p/p2P2PP/2P5/PP2PP2/RBNQKNBR w HAha - 0 9 perft 1 32 perft 2 867 @@ -4716,7 +4717,7 @@ perft 4 798722 perft 5 26632459 perft 6 781067145 -id 1 +id 524 epd rn1bknbr/pq2pppp/1p6/2pp4/P7/1P1P4/2PNPPPP/RNQBK1BR w HAha - 0 9 perft 1 24 perft 2 627 @@ -4725,7 +4726,7 @@ perft 4 462942 perft 5 13200921 perft 6 385193532 -id 1 +id 525 epd r1qk1bbr/ppp1pp1p/2np1n2/6p1/2PP4/3BP3/PP3PPP/RNQKN1BR w HAha - 2 9 perft 1 31 perft 2 992 @@ -4734,7 +4735,7 @@ perft 4 986631 perft 5 30397368 perft 6 1011631987 -id 1 +id 526 epd r1qknrbb/pppp1p2/2n3p1/4p2p/8/QPP5/P1NPPPPP/RN1K1RBB w FAfa - 2 9 perft 1 30 perft 2 702 @@ -4743,7 +4744,7 @@ perft 4 532939 perft 5 16813114 perft 6 438096194 -id 1 +id 527 epd bbkr1qnr/2pppppp/2n5/pp6/8/PPN5/1BPPPPPP/1BR1KQNR w HC - 2 9 perft 1 25 perft 2 573 @@ -4752,7 +4753,7 @@ perft 4 380910 perft 5 10554668 perft 6 283975400 -id 1 +id 528 epd 1rnbkqnr/1bpppppp/1p6/7P/p2P4/5P2/PPP1P1P1/BRNBKQNR w HBhb - 0 9 perft 1 21 perft 2 503 @@ -4761,7 +4762,7 @@ perft 4 301084 perft 5 7679979 perft 6 207799378 -id 1 +id 529 epd brnkqbnr/2p1pppp/1p6/3p4/1pP5/P6P/3PPPP1/BRNKQBNR w HBhb - 0 9 perft 1 28 perft 2 743 @@ -4770,7 +4771,7 @@ perft 4 587192 perft 5 17354516 perft 6 507176753 -id 1 +id 530 epd br1kqnrb/npp1pppp/8/3p4/p4N2/PP6/2PPPPPP/BR1KQNRB w GBgb - 0 9 perft 1 31 perft 2 808 @@ -4779,7 +4780,7 @@ perft 4 698475 perft 5 22376575 perft 6 640362920 -id 1 +id 531 epd rbbnkq1r/pppppp1p/7n/6p1/P5P1/2P2N2/1P1PPP1P/RBBNKQ1R w HAha - 1 9 perft 1 29 perft 2 580 @@ -4788,7 +4789,7 @@ perft 4 404831 perft 5 12730970 perft 6 325226128 -id 1 +id 532 epd rnbbk1nr/pp2qppp/2ppp3/8/3P4/P1N4N/1PP1PPPP/R1BBKQ1R w HAha - 0 9 perft 1 29 perft 2 838 @@ -4797,7 +4798,7 @@ perft 4 721884 perft 5 21100580 perft 6 646624429 -id 1 +id 533 epd rnbk1b1r/ppppn1pp/4pp2/7q/7P/P5PB/1PPPPP2/RNBKQ1NR w HAha - 3 9 perft 1 20 perft 2 729 @@ -4806,7 +4807,7 @@ perft 4 576199 perft 5 14507076 perft 6 498621813 -id 1 +id 534 epd r2kqnrb/pbppppp1/np5p/8/4Q1P1/3P4/PPP1PP1P/RNBK1NRB w GAga - 2 9 perft 1 47 perft 2 1219 @@ -4815,7 +4816,7 @@ perft 4 1486353 perft 5 65239153 perft 6 1834391369 -id 1 +id 535 epd rbnkbq1r/p1p2ppp/1p2pn2/3p4/P3P3/3P4/1PP1KPPP/RBN1BQNR w ha - 2 9 perft 1 29 perft 2 923 @@ -4824,7 +4825,7 @@ perft 4 883866 perft 5 26202752 perft 6 868565895 -id 1 +id 536 epd rk1bb1nr/ppppqppp/n7/1N2p3/6P1/7N/PPPPPP1P/R1KBBQ1R w HA - 6 9 perft 1 27 perft 2 703 @@ -4833,7 +4834,7 @@ perft 4 559525 perft 5 16049807 perft 6 492966455 -id 1 +id 537 epd rnkqbbnr/p1ppp2p/1p4p1/8/1B3p1P/2NP4/PPP1PPP1/R1KQ1BNR w HAha - 0 9 perft 1 29 perft 2 610 @@ -4842,7 +4843,7 @@ perft 4 438277 perft 5 14020041 perft 6 355083962 -id 1 +id 538 epd rnkqb1rb/pp1p1ppp/4p3/2P3n1/8/1PP5/P3PPPP/RNKQBNRB w GAga - 0 9 perft 1 29 perft 2 675 @@ -4851,7 +4852,7 @@ perft 4 535821 perft 5 17000613 perft 6 476598337 -id 1 +id 539 epd rb1kqnbr/pp1pp1p1/1np2p2/7p/P1P3PP/8/1P1PPP2/RBNKQNBR w HAha - 0 9 perft 1 31 perft 2 1077 @@ -4860,7 +4861,7 @@ perft 4 1183381 perft 5 37415304 perft 6 1328374620 -id 1 +id 540 epd rnkbq1br/ppp2ppp/3p4/Q3p1n1/5P2/3P2P1/PPP1P2P/RNKB1NBR w HAha - 0 9 perft 1 41 perft 2 1201 @@ -4869,7 +4870,7 @@ perft 4 1420367 perft 5 52991625 perft 6 1675608008 -id 1 +id 541 epd rn1qnbbr/pp2pppp/2ppk3/8/2PP4/3Q1N2/PP2PPPP/RNK2BBR w HA - 1 9 perft 1 34 perft 2 666 @@ -4878,7 +4879,7 @@ perft 4 472299 perft 5 15860369 perft 6 353831792 -id 1 +id 542 epd rnkqnr1b/ppppp1pp/5p2/8/Q1P2P2/8/PP1P2PP/RbK1NRBB w FAfa - 0 9 perft 1 36 perft 2 876 @@ -4887,7 +4888,7 @@ perft 4 788580 perft 5 29022529 perft 6 736717252 -id 1 +id 543 epd bbrn1nqr/ppp1k1pp/5p2/3pp3/7P/3PN3/PPP1PPP1/BBRK1NQR w - - 1 9 perft 1 24 perft 2 583 @@ -4896,7 +4897,7 @@ perft 4 383532 perft 5 10522064 perft 6 280707118 -id 1 +id 544 epd brnbkn1r/1pppp1p1/4q3/p4p1p/7P/1N3P2/PPPPP1PQ/BR1BKN1R w HBhb - 2 9 perft 1 27 perft 2 935 @@ -4905,7 +4906,7 @@ perft 4 885699 perft 5 26000648 perft 6 873063158 -id 1 +id 545 epd br1knbqr/pp2p1pp/1n6/2pp1p2/6P1/2P4B/PP1PPPQP/BRNKN2R w HBhb - 0 9 perft 1 27 perft 2 681 @@ -4914,7 +4915,7 @@ perft 4 510687 perft 5 14954779 perft 6 415624943 -id 1 +id 546 epd brnk1qrb/p1ppppp1/1p5p/8/P3n3/1N4P1/1PPPPPRP/BR1KNQ1B w Bgb - 0 9 perft 1 22 perft 2 638 @@ -4923,7 +4924,7 @@ perft 4 412346 perft 5 9760752 perft 6 293499724 -id 1 +id 547 epd rbbnknqr/pppp3p/5pp1/8/1P1pP3/7P/P1P2PP1/RBBNKNQR w HAha - 0 9 perft 1 29 perft 2 756 @@ -4932,7 +4933,7 @@ perft 4 614074 perft 5 17602252 perft 6 528140595 -id 1 +id 548 epd 1nbbknqr/rpp1ppp1/1Q1p3p/p7/2P2PP1/8/PP1PP2P/RNBBKN1R w HAh - 2 9 perft 1 37 perft 2 977 @@ -4941,7 +4942,7 @@ perft 4 944867 perft 5 33695089 perft 6 940198007 -id 1 +id 549 epd rnb2bqr/ppkpppp1/3n3p/2p5/6PP/2N2P2/PPPPP3/R1BKNBQR w HA - 2 9 perft 1 30 perft 2 647 @@ -4950,7 +4951,7 @@ perft 4 467780 perft 5 15115531 perft 6 369257622 -id 1 +id 550 epd rn1k1qrb/p1pppppp/bp6/8/4n3/P4BPP/1PPPPP2/RNBKNQR1 w GAga - 2 9 perft 1 22 perft 2 670 @@ -4959,7 +4960,7 @@ perft 4 451517 perft 5 11199653 perft 6 339919682 -id 1 +id 551 epd rb2bnqr/nppkpppp/3p4/p7/1P6/P2N2P1/2PPPP1P/RB1KBNQR w HA - 3 9 perft 1 22 perft 2 479 @@ -4968,7 +4969,7 @@ perft 4 264739 perft 5 6831555 perft 6 167329117 -id 1 +id 552 epd r1kbb1qr/2pppppp/np2n3/p7/2P3P1/8/PP1PPPQP/RNKBBN1R w HAha - 1 9 perft 1 32 perft 2 723 @@ -4977,7 +4978,7 @@ perft 4 581832 perft 5 19472074 perft 6 504622114 -id 1 +id 553 epd rnknbb1r/p1ppp1pp/8/1p1P1p1q/8/P1P5/1P2PPPP/RNKNBBQR w HAha - 1 9 perft 1 19 perft 2 607 @@ -4986,7 +4987,7 @@ perft 4 417451 perft 5 9753617 perft 6 325177085 -id 1 +id 554 epd rnkn1qrb/pp1bp1pp/2p5/1N1p1p2/8/2P5/PPKPPPPP/R2NBQRB w ga - 2 9 perft 1 27 perft 2 533 @@ -4995,7 +4996,7 @@ perft 4 330747 perft 5 9206957 perft 6 232664675 -id 1 +id 555 epd r1nknqbr/pp2p1pp/2p2p2/3p4/6P1/PP1P4/2P1PP1b/RBNKNQBR w HAha - 0 9 perft 1 20 perft 2 582 @@ -5004,7 +5005,7 @@ perft 4 409166 perft 5 10708639 perft 6 326565393 -id 1 +id 556 epd rnkb1qbr/p1pp1p1p/1p2pn2/1Q4p1/4P3/N4P2/PPPP2PP/R1KBN1BR w HAha - 0 9 perft 1 40 perft 2 1038 @@ -5013,7 +5014,7 @@ perft 4 1051441 perft 5 39145902 perft 6 1079612614 -id 1 +id 557 epd rn2qbbr/1pkppp1p/p3n1p1/8/8/2P2P2/PP1PP1PP/RNKN1BBR w HA - 0 9 perft 1 24 perft 2 605 @@ -5022,7 +5023,7 @@ perft 4 385964 perft 5 9687507 perft 6 260874068 -id 1 +id 558 epd rn1nqrbb/p1kppp1p/8/1pp3p1/1P6/2N1P3/P1PP1PPP/RK1NQRBB w - - 0 9 perft 1 21 perft 2 540 @@ -5031,7 +5032,7 @@ perft 4 337997 perft 5 8436136 perft 6 237525904 -id 1 +id 559 epd bbrnknrq/1pp3pp/p2p1p2/4p3/P7/1P2N3/2PPPPPP/BBRN1RKQ w gc - 0 9 perft 1 24 perft 2 527 @@ -5040,7 +5041,7 @@ perft 4 326175 perft 5 9139962 perft 6 226253685 -id 1 +id 560 epd brnb1nrq/pppp1kpp/4p3/8/5p1P/P1P3P1/1P1PPP2/BRNBKNRQ w GB - 1 9 perft 1 29 perft 2 773 @@ -5049,7 +5050,7 @@ perft 4 638768 perft 5 20503775 perft 6 560338709 -id 1 +id 561 epd br1k1brq/ppppp2p/1n1n1pp1/8/P1P5/3P2P1/1P2PP1P/BRNKNBRQ w GBgb - 0 9 perft 1 28 perft 2 811 @@ -5058,7 +5059,7 @@ perft 4 664880 perft 5 19913758 perft 6 565143976 -id 1 +id 562 epd 1r1knrqb/n1pppppp/p1b5/1p6/8/3N1P2/PPPPP1PP/BRNK1RQB w fb - 3 9 perft 1 29 perft 2 753 @@ -5067,7 +5068,7 @@ perft 4 620019 perft 5 20044474 perft 6 558383603 -id 1 +id 563 epd rbbnk1rq/pppppppp/8/3Pn3/8/4P1P1/PPP2P1P/RBBNKNRQ w GAga - 1 9 perft 1 22 perft 2 551 @@ -5076,7 +5077,7 @@ perft 4 324608 perft 5 8204171 perft 6 217689974 -id 1 +id 564 epd rnbbk1rq/2pppp1p/p3n1p1/1p6/P3N3/8/1PPPPPPP/RNBB1KRQ w ga - 0 9 perft 1 26 perft 2 742 @@ -5085,7 +5086,7 @@ perft 4 599527 perft 5 16787080 perft 6 525678162 -id 1 +id 565 epd rnbkn1rq/ppppppb1/6p1/7p/2B2P2/1P2P3/P1PP2PP/RNBKN1RQ w GAga - 1 9 perft 1 28 perft 2 799 @@ -5094,7 +5095,7 @@ perft 4 689436 perft 5 20755098 perft 6 639632905 -id 1 +id 566 epd rn1knrqb/p2pppp1/b1p5/1p5p/2P2P2/1P6/P2PP1PP/RNBKNRQB w FAfa - 1 9 perft 1 30 perft 2 579 @@ -5103,7 +5104,7 @@ perft 4 397545 perft 5 13257198 perft 6 311282465 -id 1 +id 567 epd rbnkbnrq/pp2p1Np/2p2p2/8/3p4/8/PPPPPPPP/RBNKBR1Q w Aga - 0 9 perft 1 23 perft 2 670 @@ -5112,7 +5113,7 @@ perft 4 501883 perft 5 13012378 perft 6 411860744 -id 1 +id 568 epd rk1bbnrq/ppp1pppp/n7/3p4/5P2/3P2NP/PPP1P1P1/RNKBB1RQ w GA - 0 9 perft 1 26 perft 2 597 @@ -5121,7 +5122,7 @@ perft 4 402506 perft 5 11269462 perft 6 296701249 -id 1 +id 569 epd r1knbbrq/pppp2p1/2n1p2p/5p2/4P3/P1PP4/1P3PPP/RNKNBBRQ w GAga - 1 9 perft 1 20 perft 2 596 @@ -5130,7 +5131,7 @@ perft 4 399069 perft 5 9416862 perft 6 293659781 -id 1 +id 570 epd rnknbrqb/p1p1pp1p/3p4/1p1N2p1/8/N7/PPPPPPPP/1RK1BRQB w Ffa - 0 9 perft 1 26 perft 2 724 @@ -5139,7 +5140,7 @@ perft 4 552040 perft 5 15257204 perft 6 461293885 -id 1 +id 571 epd rbnknrb1/1p1ppp1p/p1p3p1/8/1P3P2/1R6/PqPPP1PP/RBNKN1BQ w Afa - 0 9 perft 1 31 perft 2 1183 @@ -5148,7 +5149,7 @@ perft 4 1289502 perft 5 38722152 perft 6 1421492227 -id 1 +id 572 epd rnkbnrbq/2p1ppp1/p7/1p1p3p/3P4/1P4P1/P1P1PP1P/RNKBNRBQ w FAfa - 0 9 perft 1 24 perft 2 506 @@ -5157,7 +5158,7 @@ perft 4 301464 perft 5 8086100 perft 6 207129256 -id 1 +id 573 epd r1knrbbq/pp1ppppp/2p1n3/8/2P3P1/P7/1PKPPP1P/RN1NRBBQ w ea - 0 9 perft 1 28 perft 2 570 @@ -5166,7 +5167,7 @@ perft 4 352471 perft 5 10278695 perft 6 242592363 -id 1 +id 574 epd rnknrq1b/ppp1p1p1/4b3/3p1p1p/6P1/P4P2/1PPPPQ1P/RNKNR1BB w EAea - 2 9 perft 1 30 perft 2 739 @@ -5175,7 +5176,7 @@ perft 4 594962 perft 5 19252739 perft 6 521629794 -id 1 +id 575 epd bbqr1krn/pppp1p1p/5n2/4p1p1/3P4/P3QP2/1PP1P1PP/BB1RNKRN w GDgd - 0 9 perft 1 31 perft 2 799 @@ -5184,7 +5185,7 @@ perft 4 674913 perft 5 22172123 perft 6 609277274 -id 1 +id 576 epd bq1b1krn/pp1ppppp/3n4/2r5/3p3N/6N1/PPP1PPPP/BQRB1KR1 w GCg - 2 9 perft 1 21 perft 2 798 @@ -5193,7 +5194,7 @@ perft 4 688429 perft 5 17546069 perft 6 647165916 -id 1 +id 577 epd bqrnkbrn/2pp1pp1/p7/1p2p2p/1P6/4N3/P1PPPPPP/BQR1KBRN w GCgc - 0 9 perft 1 27 perft 2 783 @@ -5202,7 +5203,7 @@ perft 4 670798 perft 5 20059741 perft 6 624462073 -id 1 +id 578 epd bqr1krnb/1np1pppp/8/pp1p4/8/2P2N2/PP1PPPPP/BQRNKR1B w FCfc - 0 9 perft 1 28 perft 2 636 @@ -5211,7 +5212,7 @@ perft 4 461104 perft 5 14237097 perft 6 372181570 -id 1 +id 579 epd qbb1rkrn/1ppppppp/p7/7n/8/P2P4/1PP1PPPP/QBBRNKRN w Gg - 0 9 perft 1 25 perft 2 547 @@ -5220,7 +5221,7 @@ perft 4 332918 perft 5 8849383 perft 6 229112926 -id 1 +id 580 epd 1rbbnkrn/p1p1pp1p/2q5/1p1p2p1/8/2P3P1/PP1PPP1P/QRBBNKRN w GBgb - 2 9 perft 1 24 perft 2 1010 @@ -5229,7 +5230,7 @@ perft 4 983770 perft 5 24328258 perft 6 961371180 -id 1 +id 581 epd qrb1kbrn/ppp1p2p/4npp1/3p4/8/1PP4P/PR1PPPP1/Q1BNKBRN w Ggb - 1 9 perft 1 18 perft 2 451 @@ -5238,7 +5239,7 @@ perft 4 247310 perft 5 5568106 perft 6 155744022 -id 1 +id 582 epd qr2krnb/p1p1pppp/b1np4/1p6/3NP3/7P/PPPP1PP1/QRBNKR1B w FBfb - 2 9 perft 1 25 perft 2 667 @@ -5247,7 +5248,7 @@ perft 4 476030 perft 5 12458875 perft 6 361495148 -id 1 +id 583 epd qbrnbkrn/ppp3pp/3p4/5p2/2P1pP2/6PP/PP1PP3/QBRNBKRN w GCgc - 0 9 perft 1 24 perft 2 650 @@ -5256,7 +5257,7 @@ perft 4 445263 perft 5 12187382 perft 6 326834539 -id 1 +id 584 epd qrnb1krn/ppp1p1pp/5p2/2Np4/b2P4/2P5/PP2PPPP/QR1BBKRN w GBgb - 0 9 perft 1 27 perft 2 641 @@ -5265,7 +5266,7 @@ perft 4 432041 perft 5 12103076 perft 6 310695797 -id 1 +id 585 epd qrnkbbrn/pp2pp2/8/2pp2pp/6PP/3P4/PPPKPP2/QRN1BBRN w gb - 0 9 perft 1 22 perft 2 554 @@ -5274,7 +5275,7 @@ perft 4 357404 perft 5 9014737 perft 6 258925091 -id 1 +id 586 epd qrnkbrnb/p1p1ppp1/1p6/3p4/3P3p/5N1P/PPP1PPP1/QRNKBR1B w FBfb - 0 9 perft 1 24 perft 2 529 @@ -5283,7 +5284,7 @@ perft 4 318722 perft 5 8295874 perft 6 213856651 -id 1 +id 587 epd qbr1krbn/1pppp1pp/p7/5pn1/2PP4/8/PPB1PPPP/Q1RNKRBN w FCfc - 0 9 perft 1 26 perft 2 831 @@ -5292,7 +5293,7 @@ perft 4 696830 perft 5 18961456 perft 6 621884383 -id 1 +id 588 epd 1rnbkrbn/1qp1pppp/3p4/pp6/4P3/1NP4P/PP1P1PP1/QR1BKRBN w FBfb - 0 9 perft 1 24 perft 2 597 @@ -5301,7 +5302,7 @@ perft 4 404761 perft 5 10832084 perft 6 307793179 -id 1 +id 589 epd q1rkrbbn/ppp1pppp/8/3p4/1PnP4/P7/1RP1PPPP/Q1NKRBBN w Ee - 1 9 perft 1 20 perft 2 520 @@ -5310,7 +5311,7 @@ perft 4 278067 perft 5 6452205 perft 6 170268300 -id 1 +id 590 epd qrnkrn1b/ppppp1pp/4b3/7P/6p1/P7/1PPPPP2/QRNKRNBB w EBeb - 0 9 perft 1 26 perft 2 566 @@ -5319,7 +5320,7 @@ perft 4 381312 perft 5 10940750 perft 6 287987207 -id 1 +id 591 epd bbr1nkrn/ppp1pppp/3q4/3p4/8/P7/1PPPPPPP/BBRQNRKN w gc - 5 9 perft 1 19 perft 2 661 @@ -5328,7 +5329,7 @@ perft 4 460396 perft 5 10870247 perft 6 356399665 -id 1 +id 592 epd brqbnkrn/pp1pp2p/5pp1/2p5/4P3/P2P1N2/1PP2PPP/BRQB1KRN w GBgb - 0 9 perft 1 27 perft 2 679 @@ -5337,7 +5338,7 @@ perft 4 527306 perft 5 16391730 perft 6 455940859 -id 1 +id 593 epd 2qnkbrn/p1pppppp/8/1r6/1p2bP2/7N/PPPPP1PP/BR1QKBRN w GBg - 4 9 perft 1 18 perft 2 774 @@ -5346,7 +5347,7 @@ perft 4 635461 perft 5 14371755 perft 6 559579332 -id 1 +id 594 epd r1qnkr1b/p1pppppp/7n/1p6/8/1P3b1N/PRPPPPPP/B1QNK1RB w f - 5 9 perft 1 21 perft 2 677 @@ -5355,7 +5356,7 @@ perft 4 501520 perft 5 12463801 perft 6 410795298 -id 1 +id 595 epd rbbqn1rn/pppp1pp1/3k4/4p2Q/2PPP3/8/PP3PPP/RBB1NKRN w GA - 1 9 perft 1 40 perft 2 742 @@ -5364,7 +5365,7 @@ perft 4 579833 perft 5 21852196 perft 6 471452088 -id 1 +id 596 epd rqbbnkrn/3pppp1/p1p4p/1p6/5P2/P2N4/1PPPP1PP/RQBBK1RN w ga - 0 9 perft 1 23 perft 2 665 @@ -5373,7 +5374,7 @@ perft 4 492544 perft 5 12794736 perft 6 396640086 -id 1 +id 597 epd r2nkbrn/pp2pppp/8/2ppqb2/2P3P1/5P2/PP1PPN1P/RQB1KBRN w GAga - 3 9 perft 1 28 perft 2 1108 @@ -5382,7 +5383,7 @@ perft 4 1194581 perft 5 34780853 perft 6 1292405738 -id 1 +id 598 epd rqbnk1nb/p1pppr1p/5p2/1p4p1/1PP1P3/8/P2P1PPP/RQBNKRNB w FAa - 1 9 perft 1 26 perft 2 650 @@ -5391,7 +5392,7 @@ perft 4 491403 perft 5 14565370 perft 6 416833400 -id 1 +id 599 epd rbqnb1rn/p1pp1kpp/1p2pp2/8/4P2P/P5P1/1PPP1P2/RBQNBKRN w GA - 0 9 perft 1 20 perft 2 437 @@ -5400,7 +5401,7 @@ perft 4 222154 perft 5 5282124 perft 6 132309824 -id 1 +id 600 epd rqnbbkrn/p1p1pppp/3p4/1p5B/8/1P1NP3/P1PP1PPP/RQ2BKRN w GAga - 0 9 perft 1 30 perft 2 606 @@ -5409,7 +5410,7 @@ perft 4 422491 perft 5 12989786 perft 6 326601372 -id 1 +id 601 epd rqnkbbr1/ppppp1pp/5p2/7n/8/2PNP2P/PP1P1PP1/RQ1KBBRN w GAga - 1 9 perft 1 23 perft 2 482 @@ -5418,7 +5419,7 @@ perft 4 297869 perft 5 8430874 perft 6 217797292 -id 1 +id 602 epd r1nkbrnb/2ppppp1/1q6/pp5p/1P6/P3P3/2PPKPPP/RQN1BRNB w fa - 2 9 perft 1 25 perft 2 827 @@ -5427,7 +5428,7 @@ perft 4 701071 perft 5 19290675 perft 6 632892337 -id 1 +id 603 epd rbqnkrbn/p1ppppp1/7p/1p6/7P/2N1P3/PPPP1PPB/RBQ1KR1N w FAfa - 1 9 perft 1 30 perft 2 627 @@ -5436,7 +5437,7 @@ perft 4 440217 perft 5 12976682 perft 6 337377291 -id 1 +id 604 epd r1nbkrbn/p1qp1ppp/8/1pp1p3/2P1P3/6P1/PP1PBP1P/RQN1KRBN w FAfa - 2 9 perft 1 22 perft 2 616 @@ -5445,7 +5446,7 @@ perft 4 431199 perft 5 10850952 perft 6 335943324 -id 1 +id 605 epd rqnkr1bn/ppp1ppb1/3p2pp/8/P7/2P2P2/1PKPP1PP/RQN1RBBN w ea - 1 9 perft 1 31 perft 2 679 @@ -5454,7 +5455,7 @@ perft 4 493500 perft 5 15661072 perft 6 379844460 -id 1 +id 606 epd r2krnbb/qppp1ppp/1n6/p3p3/PP6/4N3/N1PPPPPP/RQ1KR1BB w EAea - 4 9 perft 1 24 perft 2 645 @@ -5463,7 +5464,7 @@ perft 4 487028 perft 5 13837270 perft 6 416239106 -id 1 +id 607 epd bbr1qk1n/1ppppp1p/2n5/p7/P7/1P2P3/2PP1PrP/1BRNQKRN w GCc - 0 9 perft 1 18 perft 2 520 @@ -5472,7 +5473,7 @@ perft 4 304462 perft 5 7215306 perft 6 207612575 -id 1 +id 608 epd brnbq1rn/2ppppkp/p5p1/1p6/8/1BP3P1/PP1PPP1P/BRN1QRKN w - - 0 9 perft 1 21 perft 2 625 @@ -5481,7 +5482,7 @@ perft 4 419667 perft 5 9929336 perft 6 300902534 -id 1 +id 609 epd brn1kbrn/pp2p1pp/3p4/q1p2p2/2P4P/6P1/PP1PPP2/BRNQKBRN w GBgb - 1 9 perft 1 18 perft 2 477 @@ -5490,7 +5491,7 @@ perft 4 273925 perft 5 6720181 perft 6 187205941 -id 1 +id 610 epd brn1krnb/p3pppp/1qpp4/1p6/2P3P1/1P6/P2PPP1P/BRNQKRNB w FBfb - 1 9 perft 1 30 perft 2 835 @@ -5499,7 +5500,7 @@ perft 4 716151 perft 5 21806428 perft 6 654487872 -id 1 +id 611 epd r1b1qkrn/1p1ppppp/p1p1n3/8/4P3/1PN5/P1PPQPPb/RBB2KRN w GAga - 0 9 perft 1 28 perft 2 825 @@ -5508,7 +5509,7 @@ perft 4 716585 perft 5 22079005 perft 6 647939781 -id 1 +id 612 epd r1bbqk1n/p1pppprp/n7/1p4p1/5P2/2N3N1/PPPPP1PP/1RBBQKR1 w Ga - 4 9 perft 1 25 perft 2 545 @@ -5517,7 +5518,7 @@ perft 4 358854 perft 5 10271111 perft 6 273864588 -id 1 +id 613 epd rnbqkbrn/p1pp1pp1/4p3/7p/2p4P/2P5/PP1PPPP1/R1BQKBRN w GAga - 0 9 perft 1 17 perft 2 445 @@ -5526,7 +5527,7 @@ perft 4 255098 perft 5 5918310 perft 6 174733195 -id 1 +id 614 epd rnbqkrnb/1p1pp1p1/2p4p/p4p2/3P2P1/7N/PPPBPP1P/RN1QKR1B w FAfa - 0 9 perft 1 34 perft 2 746 @@ -5535,7 +5536,7 @@ perft 4 623133 perft 5 21285553 perft 6 569141201 -id 1 +id 615 epd rbnqbkr1/1ppppp2/p5n1/6pp/4P3/1N6/PPPP1PPP/RBQ1BRKN w ga - 2 9 perft 1 18 perft 2 466 @@ -5544,7 +5545,7 @@ perft 4 260864 perft 5 6051500 perft 6 170135726 -id 1 +id 616 epd rnqb1krn/ppppp1p1/7p/7b/P1P2pPP/8/1P1PPP2/RNQBBKRN w GAga - 0 9 perft 1 24 perft 2 575 @@ -5553,7 +5554,7 @@ perft 4 385825 perft 5 11039042 perft 6 291243811 -id 1 +id 617 epd rnqkbbr1/p1pp1ppp/4p3/1p6/P3P2n/5P2/1PPP1NPP/RNQKBBR1 w GAga - 2 9 perft 1 27 perft 2 803 @@ -5562,7 +5563,7 @@ perft 4 694449 perft 5 20666099 perft 6 638696065 -id 1 +id 618 epd rn1kbrnb/1qppp1pp/1p6/p4p2/1B1P4/1P5N/P1P1PPPP/RNQK1R1B w FAfa - 0 9 perft 1 37 perft 2 1209 @@ -5571,7 +5572,7 @@ perft 4 1425600 perft 5 49748034 perft 6 1671593862 -id 1 +id 619 epd rbnqkrbn/Bppp1p2/p5pp/4p3/5P2/6PP/PPPPP3/RBNQKR1N w FAfa - 0 9 perft 1 29 perft 2 720 @@ -5580,7 +5581,7 @@ perft 4 534148 perft 5 15384362 perft 6 421343249 -id 1 +id 620 epd rnqbkr1n/1p1ppbpp/3p1p2/p7/8/1P6/P1PPPPPP/R1QBKRBN w FAfa - 0 9 perft 1 20 perft 2 657 @@ -5589,7 +5590,7 @@ perft 4 492678 perft 5 11843134 perft 6 413965054 -id 1 +id 621 epd rnqkrb1n/ppppp3/6p1/5p1p/2b2P2/P1N5/1PPPP1PP/RQ1KRBBN w EAea - 1 9 perft 1 28 perft 2 749 @@ -5598,7 +5599,7 @@ perft 4 543151 perft 5 15379233 perft 6 417191461 -id 1 +id 622 epd rnqk1nbb/1pp2ppp/3pr3/p3p3/3P1P2/2N3N1/PPP1P1PP/R1QKR1BB w EAa - 1 9 perft 1 29 perft 2 883 @@ -5607,7 +5608,7 @@ perft 4 815098 perft 5 25144295 perft 6 789705382 -id 1 +id 623 epd bbr1kqrn/p1p1ppp1/1p2n2p/3p4/1P1P4/2N5/P1P1PPPP/BBR1KQRN w GCgc - 0 9 perft 1 22 perft 2 485 @@ -5616,7 +5617,7 @@ perft 4 271271 perft 5 6825123 perft 6 171793012 -id 1 +id 624 epd brnbkq1n/ppp1ppr1/7p/3p2p1/2P3PP/8/PPBPPP2/BRN1KQRN w GBb - 2 9 perft 1 30 perft 2 634 @@ -5625,7 +5626,7 @@ perft 4 442537 perft 5 13674310 perft 6 345386924 -id 1 +id 625 epd brnkqbr1/1pppp1pp/5p2/p7/P1P1P2n/8/1P1P1PP1/BRNKQBRN w GBgb - 0 9 perft 1 21 perft 2 504 @@ -5634,7 +5635,7 @@ perft 4 305184 perft 5 7778289 perft 6 217596497 -id 1 +id 626 epd b1rkqrnb/p1ppp1pp/1p1n4/5p2/5P2/PN5P/1PPPP1P1/BR1KQRNB w FBf - 0 9 perft 1 23 perft 2 688 @@ -5643,7 +5644,7 @@ perft 4 531592 perft 5 14228372 perft 6 451842354 -id 1 +id 627 epd 1bbnkqrn/rppppp2/p5p1/7p/7P/P1P1P3/1P1P1PP1/RBBNKQRN w GAg - 1 9 perft 1 25 perft 2 450 @@ -5652,7 +5653,7 @@ perft 4 263946 perft 5 7752404 perft 6 185393913 -id 1 +id 628 epd rnbbkqr1/1pppppp1/7p/p3n3/PP5P/8/1BPPPPP1/RN1BKQRN w GAga - 0 9 perft 1 23 perft 2 543 @@ -5661,7 +5662,7 @@ perft 4 305812 perft 5 7549008 perft 6 199883770 -id 1 +id 629 epd r1bkqbrn/ppppp1pp/8/5p2/3nPP2/1P4N1/P1PP2PP/RNBKQBR1 w GAga - 1 9 perft 1 27 perft 2 751 @@ -5670,7 +5671,7 @@ perft 4 600417 perft 5 17989920 perft 6 527273615 -id 1 +id 630 epd rnbkqr1b/1p1pp1pp/p4p1n/2p5/1P5P/N4P2/P1PPP1P1/R1BKQRNB w FAfa - 0 9 perft 1 21 perft 2 498 @@ -5679,7 +5680,7 @@ perft 4 302278 perft 5 7808375 perft 6 216224115 -id 1 +id 631 epd rbnkbqrn/p1p3pp/1p1p4/B3pp2/3P2P1/6N1/PPP1PP1P/RBNK1QR1 w GAga - 0 9 perft 1 34 perft 2 977 @@ -5688,7 +5689,7 @@ perft 4 961128 perft 5 33318567 perft 6 978991050 -id 1 +id 632 epd r1kbbqrn/ppp3pp/2np1p2/1P2p3/3P1P2/8/P1P1P1PP/RNKBBQRN w GAga - 0 9 perft 1 32 perft 2 920 @@ -5697,7 +5698,7 @@ perft 4 844881 perft 5 26763259 perft 6 797524786 -id 1 +id 633 epd rk1qbbrn/p2npppp/1p6/2p4Q/8/4P3/PPPP1PPP/RNK1B1RN w GA - 2 9 perft 1 35 perft 2 657 @@ -5706,7 +5707,7 @@ perft 4 495406 perft 5 16662477 perft 6 419496845 -id 1 +id 634 epd rnk1brnb/pp1p1pp1/8/q1p1p2p/5P2/NP6/P1PPP1PP/R1KQBRNB w FAfa - 1 9 perft 1 26 perft 2 774 @@ -5715,7 +5716,7 @@ perft 4 610661 perft 5 16987110 perft 6 523437649 -id 1 +id 635 epd rb1kqrbn/npp1ppp1/p7/3P3p/2PP4/8/PP3PPP/RBNKQRBN w FAfa - 0 9 perft 1 35 perft 2 775 @@ -5724,7 +5725,7 @@ perft 4 661118 perft 5 23983464 perft 6 625669222 -id 1 +id 636 epd rnkb1rbn/pp1p2pp/8/2p1pp1q/P6P/1PN5/2PPPPP1/R1KBQRBN w FAfa - 1 9 perft 1 22 perft 2 899 @@ -5733,7 +5734,7 @@ perft 4 850597 perft 5 21518343 perft 6 857951339 -id 1 +id 637 epd rnkqrbbn/1pppp1p1/8/p2N1p1p/2P4P/8/PP1PPPP1/R1KQRBBN w EAea - 0 9 perft 1 29 perft 2 585 @@ -5742,7 +5743,7 @@ perft 4 393221 perft 5 12238776 perft 6 299752383 -id 1 +id 638 epd rnk1r1bb/pp1ppppp/1q4n1/2p5/5P1P/3PP3/PPP3P1/RNKQRNBB w EAea - 1 9 perft 1 27 perft 2 884 @@ -5751,7 +5752,7 @@ perft 4 811915 perft 5 23698701 perft 6 790239502 -id 1 +id 639 epd bbrnkrqn/1ppp1p2/6pp/p3p3/5PP1/2PB4/PP1PP2P/B1RNKRQN w FCfc - 0 9 perft 1 37 perft 2 693 @@ -5760,7 +5761,7 @@ perft 4 550527 perft 5 20138432 perft 6 481498664 -id 1 +id 640 epd b1rbkrqn/ppp2ppp/1n2p3/3p4/6P1/2PP4/PP2PP1P/BRNBKRQN w FBf - 1 9 perft 1 21 perft 2 463 @@ -5769,7 +5770,7 @@ perft 4 253204 perft 5 6307276 perft 6 159025909 -id 1 +id 641 epd brnkrb1n/1pp1p1pp/3p4/p1Nq1p2/2P5/8/PP1PPPPP/BRK1RBQN w eb - 2 9 perft 1 27 perft 2 725 @@ -5778,7 +5779,7 @@ perft 4 496072 perft 5 12604078 perft 6 362747791 -id 1 +id 642 epd brn1r1nb/ppppkppp/4p3/8/2PP1P2/8/PP1KP1PP/BRN1RQNB w - - 1 9 perft 1 25 perft 2 623 @@ -5787,7 +5788,7 @@ perft 4 426659 perft 5 12290985 perft 6 317097424 -id 1 +id 643 epd rbb1krqn/1pp1pp1p/p3n1p1/3pP3/8/1PN5/P1PP1PPP/RBB1KRQN w FAfa d6 0 9 perft 1 23 perft 2 529 @@ -5796,7 +5797,7 @@ perft 4 310277 perft 5 7861413 perft 6 202594556 -id 1 +id 644 epd r1bbkrqn/p1pppppp/8/4n3/1p5P/P2P2P1/1PP1PP2/RNBBKRQN w FAfa - 0 9 perft 1 23 perft 2 571 @@ -5805,7 +5806,7 @@ perft 4 346793 perft 5 8699448 perft 6 243460643 -id 1 +id 645 epd rnbkrbqn/p1pp1ppp/4p3/1p6/8/BPN3P1/P1PPPP1P/R2KRBQN w EAea - 2 9 perft 1 29 perft 2 692 @@ -5814,7 +5815,7 @@ perft 4 500375 perft 5 14904192 perft 6 386694739 -id 1 +id 646 epd rnbkrqn1/pppppp2/8/1Q2b1pp/P3P3/5P2/1PPP2PP/RNBKR1NB w EAea - 0 9 perft 1 37 perft 2 1001 @@ -5823,7 +5824,7 @@ perft 4 987842 perft 5 35626426 perft 6 993747544 -id 1 +id 647 epd rbnkbrqn/p1pppp2/7p/1p4pP/3P1P2/8/PPP1P1P1/RBNKBRQN w FAfa - 0 9 perft 1 30 perft 2 564 @@ -5832,7 +5833,7 @@ perft 4 381364 perft 5 11859538 perft 6 293703269 -id 1 +id 648 epd 1nkbbrqn/3ppppp/r1p5/pp6/8/4PP2/PPPPN1PP/RNKBBRQ1 w FAf - 2 9 perft 1 26 perft 2 546 @@ -5841,7 +5842,7 @@ perft 4 344592 perft 5 9556962 perft 6 245137199 -id 1 +id 649 epd rnkrbbq1/pppppnp1/7p/8/1B1Q1p2/3P1P2/PPP1P1PP/RNKR1B1N w DAda - 2 9 perft 1 43 perft 2 887 @@ -5850,7 +5851,7 @@ perft 4 846858 perft 5 33185346 perft 6 851927292 -id 1 +id 650 epd 1rkrbqnb/pppppp2/2n3p1/7p/3P3P/P4N2/1PP1PPP1/RNKRBQ1B w DAd - 0 9 perft 1 26 perft 2 622 @@ -5859,7 +5860,7 @@ perft 4 403921 perft 5 10786140 perft 6 285233838 -id 1 +id 651 epd rbnkr1bn/pp1pqp1p/2p1p3/6p1/3P4/7P/PPP1PPP1/RBNKRQBN w EAea - 0 9 perft 1 19 perft 2 566 @@ -5868,7 +5869,7 @@ perft 4 381197 perft 5 9107175 perft 6 293397389 -id 1 +id 652 epd r1kbrqb1/pppp2pp/2n1p1n1/5p1B/4PP2/P7/1PPP2PP/RNK1RQBN w EAea - 2 9 perft 1 39 perft 2 1359 @@ -5877,7 +5878,7 @@ perft 4 1876028 perft 5 73871486 perft 6 2633945690 -id 1 +id 653 epd rnkrqbbn/p1p3pp/1p1ppp2/8/1P6/3P2P1/PKP1PP1P/RN1RQBBN w da - 0 9 perft 1 26 perft 2 776 @@ -5886,7 +5887,7 @@ perft 4 611907 perft 5 16884013 perft 6 503561996 -id 1 +id 654 epd rnkrqnbb/ppp2p1p/3p4/4p1p1/3P3P/N1Q5/PPP1PPP1/R1KR1NBB w DAda - 0 9 perft 1 40 perft 2 1175 @@ -5895,7 +5896,7 @@ perft 4 1375884 perft 5 52620163 perft 6 1633655838 -id 1 +id 655 epd bbrnkrn1/p1pppp2/1p6/6pp/3q4/1P3QP1/P1PPPP1P/BBRNKRN1 w FCfc - 0 9 perft 1 34 perft 2 1398 @@ -5904,7 +5905,7 @@ perft 4 1712950 perft 5 57268492 perft 6 2059942014 -id 1 +id 656 epd br1bkrnq/1p2pppp/pnp5/3p4/P1P5/5P2/1P1PPKPP/BRNB1RNQ w fb - 2 9 perft 1 24 perft 2 501 @@ -5913,7 +5914,7 @@ perft 4 284936 perft 5 7049659 perft 6 177940764 -id 1 +id 657 epd brnkrbn1/pppppp1q/B6p/6p1/8/1P2PP2/P1PP2PP/BRNKR1NQ w EBeb - 0 9 perft 1 34 perft 2 815 @@ -5922,7 +5923,7 @@ perft 4 700970 perft 5 22006883 perft 6 639803952 -id 1 +id 658 epd br1krnqb/pppppp1p/1n4p1/8/8/P2NN3/2PPPPPP/BR1K1RQB w Beb - 2 9 perft 1 37 perft 2 1029 @@ -5931,7 +5932,7 @@ perft 4 1025712 perft 5 36214583 perft 6 1026195877 -id 1 +id 659 epd rbbnkr1q/p1p2ppp/1p1ppn2/8/1PP4P/8/P2PPPP1/RBBNKRNQ w FAfa - 0 9 perft 1 28 perft 2 755 @@ -5940,7 +5941,7 @@ perft 4 605106 perft 5 18972778 perft 6 513486101 -id 1 +id 660 epd r1b1krnq/pp2pppp/1bn5/2pp4/4N3/5P2/PPPPPRPP/R1BBK1NQ w Afa - 0 9 perft 1 24 perft 2 705 @@ -5949,7 +5950,7 @@ perft 4 532521 perft 5 13532966 perft 6 426443376 -id 1 +id 661 epd 1nbkrbn1/rpppppqp/p7/6p1/4P3/3P2P1/PPP1KP1P/RNB1RBNQ w e - 1 9 perft 1 31 perft 2 800 @@ -5958,7 +5959,7 @@ perft 4 693366 perft 5 21193292 perft 6 625757852 -id 1 +id 662 epd r1bkrnqb/pp3ppp/n1ppp3/8/1P5P/P7/R1PPPPP1/1NBKRNQB w Eea - 0 9 perft 1 21 perft 2 482 @@ -5967,7 +5968,7 @@ perft 4 275339 perft 5 7112890 perft 6 180378139 -id 1 +id 663 epd rbnkbrnq/ppp1p2p/5p2/3p2p1/1B1P4/1N4P1/PPP1PP1P/RB1K1RNQ w FAfa - 0 9 perft 1 33 perft 2 780 @@ -5976,7 +5977,7 @@ perft 4 628945 perft 5 20756770 perft 6 535497008 -id 1 +id 664 epd rnk1brnq/pp1ppppp/2p5/b7/8/1P2P2P/P1PP1PPQ/RNKBBRN1 w FAfa - 3 9 perft 1 29 perft 2 648 @@ -5985,7 +5986,7 @@ perft 4 449637 perft 5 13722785 perft 6 341389148 -id 1 +id 665 epd rnkrbbnq/p1p3pp/5p2/1p1pp3/P7/1PN2P2/2PPP1PP/R1KRBBNQ w DAda - 0 9 perft 1 26 perft 2 827 @@ -5994,7 +5995,7 @@ perft 4 683167 perft 5 18916370 perft 6 589161126 -id 1 +id 666 epd r1krbnqb/p1pp1ppp/2n1p3/8/1p4P1/PPP5/3PPP1P/RNKRBNQB w DAda - 1 9 perft 1 25 perft 2 540 @@ -6003,7 +6004,7 @@ perft 4 331332 perft 5 9491817 perft 6 225389422 -id 1 +id 667 epd rbnkrnbq/ppp1pp2/3p2p1/2N5/P6p/2P5/1P1PPPPP/RB1KRNBQ w EAea - 0 9 perft 1 32 perft 2 790 @@ -6012,7 +6013,7 @@ perft 4 661207 perft 5 20906017 perft 6 578332225 -id 1 +id 668 epd rnkbrn1q/1ppppppb/8/p4N1p/8/P1N5/1PPPPPPP/R1KBR1BQ w EAea - 0 9 perft 1 31 perft 2 691 @@ -6021,7 +6022,7 @@ perft 4 510665 perft 5 15308408 perft 6 404129987 -id 1 +id 669 epd rnkrnbbq/p1p2ppp/3pp3/1p6/6P1/4PQ1B/PPPP1P1P/RNKRN1B1 w DAda - 0 9 perft 1 29 perft 2 558 @@ -6030,7 +6031,7 @@ perft 4 352887 perft 5 10825379 perft 6 246965507 -id 1 +id 670 epd rnkrnqbb/pp2p1p1/3p3p/2p2p2/5P2/1P1N4/P1PPPQPP/RNKR2BB w DAda - 0 9 perft 1 29 perft 2 762 @@ -6039,7 +6040,7 @@ perft 4 644936 perft 5 20522675 perft 6 596067005 -id 1 +id 671 epd bb1rknnr/ppqppppp/8/2p5/3P1N2/1P6/P1P1PPPP/BBQRKN1R w HDhd - 1 9 perft 1 33 perft 2 963 @@ -6048,7 +6049,7 @@ perft 4 1000890 perft 5 34552118 perft 6 1124738493 -id 1 +id 672 epd bqrbknnr/ppp1p2p/8/3p1p2/5p2/P3N2P/1PPPP1P1/BQRBK1NR w HChc - 0 9 perft 1 20 perft 2 398 @@ -6057,7 +6058,7 @@ perft 4 194859 perft 5 4834319 perft 6 113660536 -id 1 +id 673 epd b1rk1bnr/qpp1pppp/p4n2/3p4/3PPP2/7N/PPP3PP/BQRKNB1R w HChc - 1 9 perft 1 25 perft 2 648 @@ -6066,7 +6067,7 @@ perft 4 455720 perft 5 12200870 perft 6 351766307 -id 1 +id 674 epd bqkrnnrb/pppp2p1/4pp2/4P2p/6P1/7P/PPPP1P2/BQRKNNRB w GC - 1 9 perft 1 30 perft 2 493 @@ -6075,7 +6076,7 @@ perft 4 280726 perft 5 8786998 perft 6 181492621 -id 1 +id 675 epd q1brknnr/1p1ppppp/p7/2p5/8/1PPP4/P2RPPPP/QBB1KNNR w Hhd - 0 9 perft 1 25 perft 2 501 @@ -6084,7 +6085,7 @@ perft 4 290463 perft 5 7982978 perft 6 192717198 -id 1 +id 676 epd qrb1k1nr/ppppb1pp/6n1/4ppN1/3P4/4N3/PPP1PPPP/QRBBK2R w HBhb - 2 9 perft 1 31 perft 2 872 @@ -6093,7 +6094,7 @@ perft 4 739276 perft 5 22493014 perft 6 646855304 -id 1 +id 677 epd 1rbknbnr/1ppp1pp1/q6p/p3p3/5P2/2PPB3/PP2P1PP/QR1KNBNR w HBhb - 0 9 perft 1 28 perft 2 1020 @@ -6102,7 +6103,7 @@ perft 4 984000 perft 5 27484692 perft 6 947786800 -id 1 +id 678 epd qrbk2rb/1ppp1ppp/5nn1/p3p3/1N6/P7/1PPPPPPP/QRB1KNRB w gb - 0 9 perft 1 23 perft 2 592 @@ -6111,7 +6112,7 @@ perft 4 395716 perft 5 10098215 perft 6 293988585 -id 1 +id 679 epd qbrk1nnr/1pp1pppp/2b5/p2p4/P2P2P1/8/1PP1PP1P/QBKRBNNR w hc - 1 9 perft 1 26 perft 2 654 @@ -6120,7 +6121,7 @@ perft 4 471653 perft 5 13740891 perft 6 373081138 -id 1 +id 680 epd qrkbbnnr/ppp2p1p/4p3/3p2p1/P7/2PP4/1P2PPPP/QRKBBNNR w HBhb - 0 9 perft 1 25 perft 2 626 @@ -6129,7 +6130,7 @@ perft 4 431634 perft 5 12079406 perft 6 324006164 -id 1 +id 681 epd qr1kbbnr/ppp1pp1p/4n1p1/2Pp4/6P1/4N3/PP1PPP1P/QRK1BBNR w HB d6 0 9 perft 1 26 perft 2 699 @@ -6138,7 +6139,7 @@ perft 4 497152 perft 5 13353359 perft 6 375702908 -id 1 +id 682 epd qrk1b1rb/p1pppppp/3nnQ2/1p6/1P3P2/3P4/P1P1P1PP/1RKNBNRB w GBgb - 3 9 perft 1 43 perft 2 1369 @@ -6147,7 +6148,7 @@ perft 4 1831200 perft 5 71514365 perft 6 2427477375 -id 1 +id 683 epd qbrk1nbr/pppp3p/5n2/4ppp1/3P1P2/4N3/PPP1P1PP/QBKRN1BR w hc - 0 9 perft 1 25 perft 2 752 @@ -6156,7 +6157,7 @@ perft 4 615263 perft 5 17493373 perft 6 543180234 -id 1 +id 684 epd qrkb1nbr/1pppppQp/3n4/p7/5p2/1P1N4/P1PPP1PP/1RKB1NBR w HBhb - 0 9 perft 1 45 perft 2 946 @@ -6165,7 +6166,7 @@ perft 4 966903 perft 5 39736157 perft 6 1051910977 -id 1 +id 685 epd qrk1nbbr/ppp1p1p1/4n2p/3p1p2/1P5P/3P2P1/P1P1PP2/QRKNNBBR w HBhb - 1 9 perft 1 32 perft 2 770 @@ -6174,7 +6175,7 @@ perft 4 646977 perft 5 21717615 perft 6 577979364 -id 1 +id 686 epd qrkn1rbb/pp2pppp/2p5/3p4/P2Qn1P1/1P6/2PPPP1P/1RKNNRBB w FBfb - 0 9 perft 1 38 perft 2 943 @@ -6183,7 +6184,7 @@ perft 4 868165 perft 5 31909835 perft 6 798405123 -id 1 +id 687 epd bbrqknnr/ppp4p/3pp3/5pp1/4PP2/5Q2/PPPP2PP/BBR1KNNR w HChc - 0 9 perft 1 36 perft 2 843 @@ -6192,7 +6193,7 @@ perft 4 758528 perft 5 26828059 perft 6 723306114 -id 1 +id 688 epd 1rqbkn1r/p1p1pppp/1p5n/P2p4/3Pb1P1/8/1PP1PP1P/BRQBKNNR w HBhb - 0 9 perft 1 23 perft 2 778 @@ -6201,7 +6202,7 @@ perft 4 649789 perft 5 17337683 perft 6 579112676 -id 1 +id 689 epd br1knbnr/1qp1pppp/pp1p4/8/8/PP6/2PPPPPP/BRQKNBNR w HBhb - 2 9 perft 1 26 perft 2 697 @@ -6210,7 +6211,7 @@ perft 4 546622 perft 5 15280079 perft 6 473071890 -id 1 +id 690 epd brqk2rb/ppppp1pp/4np2/8/2n5/3P1Q2/PP2PPPP/BR1KNNRB w GBgb - 0 9 perft 1 32 perft 2 948 @@ -6219,7 +6220,7 @@ perft 4 885713 perft 5 29821322 perft 6 874251866 -id 1 +id 691 epd r1bqknnr/pp1pp1p1/5p1p/2p1b2N/2P5/8/PPQPPPPP/RBB1K1NR w HAha - 0 9 perft 1 31 perft 2 785 @@ -6228,7 +6229,7 @@ perft 4 659952 perft 5 22244193 perft 6 592797491 -id 1 +id 692 epd rqbbknnr/ppppp2p/5pp1/8/8/1P3PP1/PQPPP2P/R1BBKNNR w HAha - 0 9 perft 1 23 perft 2 391 @@ -6237,7 +6238,7 @@ perft 4 198450 perft 5 5576671 perft 6 121267576 -id 1 +id 693 epd rqbknbnr/1pp1p2p/p7/3p1pp1/7N/1PP5/P2PPPPP/RQBK1BNR w HAha - 0 9 perft 1 27 perft 2 676 @@ -6246,7 +6247,7 @@ perft 4 522428 perft 5 15955388 perft 6 448477218 -id 1 +id 694 epd rqb1nnrb/2ppkppp/1p2p3/p7/2PPP3/1P6/P4PPP/RQBKNNRB w GA - 1 9 perft 1 31 perft 2 727 @@ -6255,7 +6256,7 @@ perft 4 570647 perft 5 18361051 perft 6 483248153 -id 1 +id 695 epd rb1kbn1r/p1ppppp1/qp5n/7p/P7/RPP5/3PPPPP/1BQKBNNR w Hha - 2 9 perft 1 29 perft 2 837 @@ -6264,7 +6265,7 @@ perft 4 730083 perft 5 21279560 perft 6 682863811 -id 1 +id 696 epd rqkbb1nr/p1p2ppp/1p1p2n1/3Np3/4P3/5N2/PPPP1PPP/RQKBB2R w HAha - 0 9 perft 1 28 perft 2 717 @@ -6273,7 +6274,7 @@ perft 4 550987 perft 5 16347343 perft 6 453153783 -id 1 +id 697 epd rqknbbr1/p1pppp1p/1p3np1/8/4P3/2P2P1P/PP1P2P1/RQKNBBNR w HAa - 0 9 perft 1 27 perft 2 650 @@ -6282,7 +6283,7 @@ perft 4 475303 perft 5 13847463 perft 6 383256006 -id 1 +id 698 epd r1k1bnrb/1qpppppp/1p2n3/p7/1P5P/6P1/P1PPPP2/RQKNBNR1 w GAga - 1 9 perft 1 24 perft 2 806 @@ -6291,7 +6292,7 @@ perft 4 713220 perft 5 19382263 perft 6 686009788 -id 1 +id 699 epd rb1knnbr/1pp1ppp1/p2p3p/5q2/3B2P1/3P1P2/PPP1P2P/RBQKNN1R w HAha - 0 9 perft 1 34 perft 2 1360 @@ -6300,7 +6301,7 @@ perft 4 1605706 perft 5 51973672 perft 6 1837704407 -id 1 +id 700 epd rqkb1nbr/p1p1ppp1/1p3n1p/2Qp4/8/2P5/PP1PPPPP/R1KBNNBR w HAha - 2 9 perft 1 39 perft 2 983 @@ -6309,7 +6310,7 @@ perft 4 940989 perft 5 36347815 perft 6 918801645 -id 1 +id 701 epd rqknnbbr/2pppp2/pp5p/6p1/1P1P4/4PP2/P1P3PP/RQKNNBBR w HAha - 0 9 perft 1 26 perft 2 628 @@ -6318,7 +6319,7 @@ perft 4 464924 perft 5 13787303 perft 6 386125234 -id 1 +id 702 epd rqkn1rbb/1pp1pppp/p7/3p4/3Pn3/2P1PP2/PP4PP/RQKNNRBB w FAfa - 1 9 perft 1 20 perft 2 527 @@ -6327,7 +6328,7 @@ perft 4 321533 perft 5 8082183 perft 6 219311659 -id 1 +id 703 epd bbrkqn1r/1pppppp1/5n2/p7/1PP2P1p/7N/P2PP1PP/BBRKQN1R w HChc - 1 9 perft 1 36 perft 2 963 @@ -6336,7 +6337,7 @@ perft 4 973839 perft 5 35907489 perft 6 1034223364 -id 1 +id 704 epd brkbqn1r/p2ppppp/7n/1p6/P1p3PP/8/1PPPPP1N/BRKBQ1NR w HBhb - 0 9 perft 1 18 perft 2 583 @@ -6345,7 +6346,7 @@ perft 4 394603 perft 5 8858385 perft 6 304339862 -id 1 +id 705 epd brkq1bnr/pp1ppp1p/8/2p2np1/P7/8/1PPPPPPP/BRKQNBNR w HBhb - 0 9 perft 1 19 perft 2 552 @@ -6354,7 +6355,7 @@ perft 4 354260 perft 5 8432183 perft 6 262293169 -id 1 +id 706 epd brkqnnrb/1ppppppp/8/8/p3P3/5N2/PPPP1PPP/BRKQ1NRB w GBgb - 3 9 perft 1 21 perft 2 397 @@ -6363,7 +6364,7 @@ perft 4 204350 perft 5 5489836 perft 6 128389738 -id 1 +id 707 epd rbbkq1nr/1p2pppp/p1p3nB/3p4/1Q1P4/6N1/PPP1PPPP/RB1K2NR w HAha - 0 9 perft 1 40 perft 2 1132 @@ -6372,7 +6373,7 @@ perft 4 1260470 perft 5 47425783 perft 6 1415578783 -id 1 +id 708 epd rkbbq1nr/1pppp1p1/4np2/p6p/8/PP3P2/1KPPP1PP/R1BBQNNR w ha - 0 9 perft 1 24 perft 2 596 @@ -6381,7 +6382,7 @@ perft 4 402121 perft 5 10822049 perft 6 302056813 -id 1 +id 709 epd r1bqn1nr/pkpppp1p/1p4pb/8/PN6/R7/1PPPPPPP/1KBQ1BNR w H - 2 9 perft 1 33 perft 2 794 @@ -6390,7 +6391,7 @@ perft 4 649150 perft 5 20919309 perft 6 561073410 -id 1 +id 710 epd rkb1nnrb/1pppq1pp/p4p2/4p3/5P2/1P1PB3/P1P1P1PP/RK1QNNRB w GAga - 0 9 perft 1 26 perft 2 625 @@ -6399,7 +6400,7 @@ perft 4 442036 perft 5 12515042 perft 6 342967558 -id 1 +id 711 epd rbkqbn1r/pppp1p1p/2n1p1p1/8/8/1P1PP1N1/P1P2PPP/RBKQB1NR w HAha - 1 9 perft 1 30 perft 2 660 @@ -6408,7 +6409,7 @@ perft 4 492714 perft 5 15348335 perft 6 403323883 -id 1 +id 712 epd rkqbb1n1/pppppppr/8/6np/5P2/8/PPPPP1PP/RKQBBNNR w HAa - 6 9 perft 1 23 perft 2 500 @@ -6417,7 +6418,7 @@ perft 4 292936 perft 5 7519117 perft 6 196524441 -id 1 +id 713 epd rkqnbbnr/ppppppp1/8/7p/3N4/6PP/PPPPPP2/RKQNBB1R w HAa - 0 9 perft 1 24 perft 2 484 @@ -6426,7 +6427,7 @@ perft 4 284570 perft 5 7775173 perft 6 193947530 -id 1 +id 714 epd rkqnb1rb/p1p1pppp/1p1p4/2n5/3P4/2P1N1N1/PP2PPPP/RKQ1B1RB w GAga - 0 9 perft 1 28 perft 2 1020 @@ -6435,7 +6436,7 @@ perft 4 1027904 perft 5 30515456 perft 6 1073711823 -id 1 +id 715 epd rbk1nnbr/1ppq1ppp/p2p4/4p3/P3B2P/2P5/1P1PPPP1/R1KQNNBR w HAha - 2 9 perft 1 38 perft 2 998 @@ -6444,7 +6445,7 @@ perft 4 1047592 perft 5 38552638 perft 6 1139322479 -id 1 +id 716 epd r1qbn1br/k1pppppp/6n1/pp6/5P1P/P7/1PPPP1PB/RKQBNN1R w HA - 1 9 perft 1 22 perft 2 549 @@ -6453,7 +6454,7 @@ perft 4 348574 perft 5 8725809 perft 6 251613569 -id 1 +id 717 epd rkqnn1br/pppp3p/4p1pb/5p2/P2P4/7P/1PP1PPPB/RKQNNB1R w HAha - 1 9 perft 1 32 perft 2 659 @@ -6462,7 +6463,7 @@ perft 4 469701 perft 5 15434721 perft 6 365761521 -id 1 +id 718 epd rk1nnrbb/p1p1pppp/1p6/3p1q2/P3P3/2NN4/1PPP1PPP/RKQ2RBB w FAfa - 3 9 perft 1 29 perft 2 989 @@ -6471,7 +6472,7 @@ perft 4 980477 perft 5 29643404 perft 6 998848556 -id 1 +id 719 epd bbrk1q1r/ppppppp1/3n4/7p/3Pn3/6PN/PPP1PPNP/BBRK1Q1R w HChc - 2 9 perft 1 23 perft 2 712 @@ -6480,7 +6481,7 @@ perft 4 516177 perft 5 12995202 perft 6 411077508 -id 1 +id 720 epd brkbnq1r/p1ppp2p/5ppn/1p6/5P2/1P1P2P1/P1P1P2P/BRKBNQNR w HBhb - 0 9 perft 1 28 perft 2 856 @@ -6489,7 +6490,7 @@ perft 4 780503 perft 5 23529352 perft 6 754501112 -id 1 +id 721 epd br1k1bnr/ppppp1pp/4np2/1B2P2q/3P4/8/PPP2PPP/BRKNQ1NR w HB - 3 9 perft 1 36 perft 2 1214 @@ -6498,7 +6499,7 @@ perft 4 1328331 perft 5 45096834 perft 6 1470987023 -id 1 +id 722 epd brk1qnrb/pnppp1p1/1p6/5p1p/8/5PPP/PPPPP1R1/BRKNQN1B w Bgb - 0 9 perft 1 22 perft 2 551 @@ -6507,7 +6508,7 @@ perft 4 353317 perft 5 9040545 perft 6 259643605 -id 1 +id 723 epd rbbkn1nr/1ppp2pp/p3p3/2q2p2/3P4/6P1/PPPBPP1P/RB1KNQNR w HAha - 0 9 perft 1 31 perft 2 1060 @@ -6516,7 +6517,7 @@ perft 4 1015099 perft 5 30314172 perft 6 976268967 -id 1 +id 724 epd rkbbn1nr/ppppp1pp/8/6N1/5p2/1q6/P1PPPPPP/RKBBN1QR w HAha - 0 9 perft 1 3 perft 2 72 @@ -6525,7 +6526,7 @@ perft 4 50827 perft 5 1400832 perft 6 39654253 -id 1 +id 725 epd rkb2bnr/pp2pppp/2p1n3/3p4/q2P4/5NP1/PPP1PP1P/RKBNQBR1 w Aha - 0 9 perft 1 29 perft 2 861 @@ -6534,7 +6535,7 @@ perft 4 763454 perft 5 22763215 perft 6 731511256 -id 1 +id 726 epd rkbq1nrb/ppppppp1/7p/8/1P1n4/P4P1P/2PPP1P1/RKBNQNRB w GAga - 0 9 perft 1 25 perft 2 672 @@ -6543,7 +6544,7 @@ perft 4 473864 perft 5 12954224 perft 6 361237536 -id 1 +id 727 epd rbknb1nr/ppp1qp1p/6p1/3pp3/3P3P/2B1P3/PPP2PP1/RBKN1QNR w HAha - 1 9 perft 1 27 perft 2 857 @@ -6552,7 +6553,7 @@ perft 4 792538 perft 5 23790033 perft 6 768247869 -id 1 +id 728 epd rknbbq1r/p1pppppp/1p2N3/8/3n4/2P5/PP1PPPPP/RK1BBQNR w HAha - 4 9 perft 1 29 perft 2 763 @@ -6561,7 +6562,7 @@ perft 4 574054 perft 5 16926075 perft 6 447896703 -id 1 +id 729 epd r1nqbbnr/1pppp1pp/1k6/p4p2/8/4P3/PPPP1PPP/RKN1BBNR w HA - 0 9 perft 1 26 perft 2 658 @@ -6570,7 +6571,7 @@ perft 4 464039 perft 5 12380488 perft 6 349047256 -id 1 +id 730 epd rkn2qrb/ppp1pppp/6n1/1b1p4/1P6/4PPB1/P1PP2PP/RKNQ1NRB w GAga - 3 9 perft 1 23 perft 2 574 @@ -6579,7 +6580,7 @@ perft 4 370324 perft 5 9501401 perft 6 263870337 -id 1 +id 731 epd rbkn2br/ppppp1p1/4np1p/1P5q/8/2P1N3/P2PPPPP/RBK1QNBR w HAha - 1 9 perft 1 29 perft 2 992 @@ -6588,7 +6589,7 @@ perft 4 999564 perft 5 30148787 perft 6 1045942540 -id 1 +id 732 epd 1knbqnbr/1ppppp1p/r5p1/p7/7P/2PN2P1/PP1PPP2/RK1BQNBR w HAh - 2 9 perft 1 26 perft 2 698 @@ -6597,7 +6598,7 @@ perft 4 512023 perft 5 14848229 perft 6 402599313 -id 1 +id 733 epd rk1qnbbr/pnpppp1p/6p1/1p6/3P4/1P6/P1P1PPPP/RKNQNBBR w HAha - 1 9 perft 1 20 perft 2 480 @@ -6606,7 +6607,7 @@ perft 4 287539 perft 5 7425917 perft 6 203194521 -id 1 +id 734 epd rknqnrbb/pp1p2p1/5p1p/2p1p3/2P1P3/P2P4/1P3PPP/RKNQNRBB w FAfa - 0 9 perft 1 26 perft 2 679 @@ -6615,7 +6616,7 @@ perft 4 494953 perft 5 13790137 perft 6 392629571 -id 1 +id 735 epd bbrk2qr/pp1p1ppp/3n2n1/2p1p3/3P1P2/6N1/PPP1P1PP/BBRKN1QR w HChc - 0 9 perft 1 26 perft 2 790 @@ -6624,7 +6625,7 @@ perft 4 673269 perft 5 19259490 perft 6 617563700 -id 1 +id 736 epd b1krnnqr/1p1ppppp/p1p5/b6B/P7/4P1N1/1PPP1PPP/BRK1N1QR w HB - 2 9 perft 1 26 perft 2 625 @@ -6633,7 +6634,7 @@ perft 4 415452 perft 5 11490615 perft 6 304805107 -id 1 +id 737 epd 1rknnbqr/3ppppp/p7/1pp5/4b2P/P4P2/1PPPP1PR/BRKNNBQ1 w Bhb - 1 9 perft 1 24 perft 2 757 @@ -6642,7 +6643,7 @@ perft 4 618777 perft 5 17275100 perft 6 544309489 -id 1 +id 738 epd br1nn1rb/pppkpqpp/3p1p2/8/PP6/4N3/1KPPPPPP/BR2NQRB w - - 3 9 perft 1 24 perft 2 682 @@ -6651,7 +6652,7 @@ perft 4 482711 perft 5 13057308 perft 6 375033550 -id 1 +id 739 epd rbbkn1qr/pppp2p1/6np/4pp2/7N/7P/PPPPPPPR/RBBK1NQ1 w Aha - 0 9 perft 1 22 perft 2 586 @@ -6660,7 +6661,7 @@ perft 4 409891 perft 5 10607781 perft 6 324452612 -id 1 +id 740 epd rk1bn1qr/pppbpppp/4n3/4p3/4P3/5P2/PPPP2PP/RKBB1NQR w HAha - 1 9 perft 1 22 perft 2 530 @@ -6669,7 +6670,7 @@ perft 4 348004 perft 5 9514787 perft 6 259898748 -id 1 +id 741 epd rkbnnbqr/1ppp1ppp/p7/4p3/8/QP3P2/P1PPP1PP/RKBNNB1R w HAha - 0 9 perft 1 29 perft 2 705 @@ -6678,7 +6679,7 @@ perft 4 551042 perft 5 17524731 perft 6 472356665 -id 1 +id 742 epd 1kbnnqrb/1pp1p1pp/r4p2/p2p4/N4P2/3P4/PPP1P1PP/RKB1NQRB w GAg - 2 9 perft 1 21 perft 2 623 @@ -6687,7 +6688,7 @@ perft 4 437554 perft 5 11601134 perft 6 343214006 -id 1 +id 743 epd rbknbn1r/pppp1p1p/4p1q1/8/P1P3Pp/8/1P1PPP2/RBKNBNQR w HAha - 0 9 perft 1 30 perft 2 813 @@ -6696,7 +6697,7 @@ perft 4 708454 perft 5 23379040 perft 6 692576573 -id 1 +id 744 epd rk1bb1qr/2pppppp/p2nn3/1p4P1/6QP/8/PPPPPP2/RKNBBN1R w HAha - 2 9 perft 1 36 perft 2 857 @@ -6705,7 +6706,7 @@ perft 4 757524 perft 5 26485812 perft 6 696999449 -id 1 +id 745 epd rkn1bbqr/p2ppppp/2p1n3/1p6/4PP2/6PP/PPPP4/RKNNBBQR w HAha - 0 9 perft 1 33 perft 2 687 @@ -6714,7 +6715,7 @@ perft 4 511018 perft 5 17101732 perft 6 412778368 -id 1 +id 746 epd rkn1bqrb/pnp1pppp/3p4/8/Pp6/1N2NP2/1PPPP1PP/RK2BQRB w GAga - 0 9 perft 1 28 perft 2 591 @@ -6723,7 +6724,7 @@ perft 4 406025 perft 5 12182448 perft 6 312575205 -id 1 +id 747 epd rbk1n1br/ppp1ppqp/2n5/2Np2p1/8/2P5/PPBPPPPP/R1KN1QBR w HAha - 4 9 perft 1 35 perft 2 930 @@ -6732,7 +6733,7 @@ perft 4 844433 perft 5 27160490 perft 6 780616047 -id 1 +id 748 epd rknbn1br/1ppp1ppp/p3p3/8/1q6/2P2N1P/P2PPPP1/RKNB1QBR w HAha - 0 9 perft 1 4 perft 2 157 @@ -6741,7 +6742,7 @@ perft 4 138102 perft 5 3454704 perft 6 125373395 -id 1 +id 749 epd rkn1qbbr/pp3ppp/4n3/2ppp3/4P1P1/P2P4/1PP2P1P/RKNNQBBR w HAha - 0 9 perft 1 28 perft 2 840 @@ -6750,7 +6751,7 @@ perft 4 771328 perft 5 23200961 perft 6 756489357 -id 1 +id 750 epd rkn1qrbb/pp1ppp2/2p1n1p1/7p/2P2P1P/6P1/PP1PP3/RKNNQRBB w FAfa - 1 9 perft 1 32 perft 2 867 @@ -6759,7 +6760,7 @@ perft 4 757836 perft 5 24485663 perft 6 688115847 -id 1 +id 751 epd b1rknnrq/bpppp1p1/p6p/5p1P/6P1/4N3/PPPPPP2/BBRKN1RQ w GCgc - 1 9 perft 1 33 perft 2 851 @@ -6768,7 +6769,7 @@ perft 4 763967 perft 5 26686205 perft 6 731944177 -id 1 +id 752 epd brkb1nr1/pppppp2/3n2pp/3B4/1P6/4P3/PqPP1PPP/BRK1NNRQ w GBgb - 2 9 perft 1 4 perft 2 98 @@ -6777,7 +6778,7 @@ perft 4 76143 perft 5 2352530 perft 6 64251468 -id 1 +id 753 epd brk1nbrq/1ppppn1p/6p1/p4p2/P5P1/5R2/1PPPPP1P/BRKNNB1Q w Bgb - 0 9 perft 1 29 perft 2 922 @@ -6786,7 +6787,7 @@ perft 4 879527 perft 5 27463717 perft 6 888881062 -id 1 +id 754 epd brkn1rqb/1p1ppppp/3n4/p1p5/1P3P2/8/PNPPP1PP/BR1KNRQB w fb - 1 9 perft 1 29 perft 2 633 @@ -6795,7 +6796,7 @@ perft 4 469818 perft 5 15076198 perft 6 396737074 -id 1 +id 755 epd rb1k1nrq/pbp1pppp/1p1p1n2/8/5P2/4NN1P/PPPPP1P1/RBBK2RQ w GAga - 2 9 perft 1 28 perft 2 841 @@ -6804,7 +6805,7 @@ perft 4 710751 perft 5 20772996 perft 6 613798447 -id 1 +id 756 epd rkbbnnrq/p1pp3p/4p1p1/1p3p2/P6P/1P6/1BPPPPP1/RK1BNNRQ w GAga - 0 9 perft 1 33 perft 2 957 @@ -6813,7 +6814,7 @@ perft 4 907217 perft 5 29735654 perft 6 903933626 -id 1 +id 757 epd rk2nbrq/p1ppppp1/bpn5/7p/6P1/2N2P2/PPPPP1QP/RKB1NBR1 w GAga - 2 9 perft 1 24 perft 2 687 @@ -6822,7 +6823,7 @@ perft 4 544627 perft 5 15518417 perft 6 484217179 -id 1 +id 758 epd rkbn1r1b/pp1pppnp/6q1/2p3p1/5P1P/4N3/PPPPP1P1/RKB1NRQB w FAfa - 1 9 perft 1 23 perft 2 831 @@ -6831,7 +6832,7 @@ perft 4 754622 perft 5 21126103 perft 6 744755212 -id 1 +id 759 epd rbknb1rq/ppp1p1p1/3pnp1p/8/6PP/2PP4/PP2PP2/RBKNBNRQ w GAga - 0 9 perft 1 31 perft 2 838 @@ -6840,7 +6841,7 @@ perft 4 736910 perft 5 24008129 perft 6 677776408 -id 1 +id 760 epd rknbb1rq/p1pn1ppp/4p3/1p1p4/2P5/1P2N1P1/P2PPP1P/RKNBB1RQ w GAga - 1 9 perft 1 29 perft 2 830 @@ -6849,7 +6850,7 @@ perft 4 721630 perft 5 22243832 perft 6 660040360 -id 1 +id 761 epd rk1nbbrq/pp1p1ppp/3n4/P3p3/2p4P/8/1PPPPPP1/RKNNBBRQ w GAga - 1 9 perft 1 24 perft 2 484 @@ -6858,7 +6859,7 @@ perft 4 297419 perft 5 8379748 perft 6 214004367 -id 1 +id 762 epd rknnbr1b/ppp2pqp/3p4/4p1p1/7P/3P1P2/PPP1P1P1/RKNNBRQB w FAfa - 0 9 perft 1 32 perft 2 838 @@ -6867,7 +6868,7 @@ perft 4 740701 perft 5 23472124 perft 6 699211365 -id 1 +id 763 epd rb1k1rbq/ppppN1pp/2nn4/5p2/7P/8/PPPPPPP1/RBK1NRBQ w FA - 1 9 perft 1 27 perft 2 800 @@ -6876,7 +6877,7 @@ perft 4 701742 perft 5 20804424 perft 6 660917073 -id 1 +id 764 epd r1nbnrbq/kppppp1p/6p1/8/p1PP1P2/4P3/PP4PP/RKNBNRBQ w FA - 1 9 perft 1 28 perft 2 757 @@ -6885,7 +6886,7 @@ perft 4 602699 perft 5 17180857 perft 6 507618340 -id 1 +id 765 epd rkn1rbbq/p1pppppp/2n5/1pP5/8/1N2P3/PP1P1PPP/RK1NRBBQ w EAea - 1 9 perft 1 22 perft 2 483 @@ -6894,7 +6895,7 @@ perft 4 283679 perft 5 7497674 perft 6 191130942 -id 1 +id 766 epd rknnrqbb/2pppppp/8/p7/Np3P2/3P4/PPP1P1PP/RKN1RQBB w EAea - 0 9 perft 1 25 perft 2 536 @@ -6903,7 +6904,7 @@ perft 4 339180 perft 5 9694947 perft 6 245669668 -id 1 +id 767 epd bb1rknrn/1qppppp1/1p4B1/p6N/8/2P5/PP1PPPPP/B1QRK1RN w GDgd - 1 9 perft 1 32 perft 2 715 @@ -6912,7 +6913,7 @@ perft 4 575008 perft 5 17860156 perft 6 502410909 -id 1 +id 768 epd b1rbknrn/qpp1ppp1/p6p/3p4/2P5/1P1P1P2/P3P1PP/BQRBKNRN w GCgc - 0 9 perft 1 30 perft 2 818 @@ -6921,7 +6922,7 @@ perft 4 688711 perft 5 20981488 perft 6 611986786 -id 1 +id 769 epd bqkrnbrn/1pp1pp1p/p7/1B1p2p1/4P3/7P/PPPP1PP1/BQKRN1RN w - - 0 9 perft 1 28 perft 2 676 @@ -6930,7 +6931,7 @@ perft 4 478054 perft 5 13126287 perft 6 363765666 -id 1 +id 770 epd bqrknrnb/1p2ppp1/p1pp3p/8/3P1P2/1PP5/P3P1PP/BQRKNRNB w FCfc - 0 9 perft 1 31 perft 2 646 @@ -6939,7 +6940,7 @@ perft 4 455607 perft 5 14984618 perft 6 349082278 -id 1 +id 771 epd qbbrkn1r/pppppp1p/8/6p1/2P1Pn1P/6N1/PP1P1PP1/QBBRKNR1 w GDd - 3 9 perft 1 20 perft 2 532 @@ -6948,7 +6949,7 @@ perft 4 303586 perft 5 7512432 perft 6 202967948 -id 1 +id 772 epd 1rbbknr1/p1ppp1pp/1pq2pn1/8/3P4/P3P3/QPP2PPP/1RBBKNRN w GBgb - 3 9 perft 1 31 perft 2 1002 @@ -6957,7 +6958,7 @@ perft 4 999607 perft 5 30642468 perft 6 1009228283 -id 1 +id 773 epd qrbkn1rn/pppp1ppp/8/6b1/P1P1Pp2/8/1P1P2PP/QRBKNBRN w GBgb - 0 9 perft 1 22 perft 2 505 @@ -6966,7 +6967,7 @@ perft 4 304863 perft 5 8192621 perft 6 214730959 -id 1 +id 774 epd qrbk1rnb/p2ppp1p/5n2/1pp3p1/8/7P/PPPPPPPN/QRBKR1NB w Bfb - 0 9 perft 1 20 perft 2 619 @@ -6975,7 +6976,7 @@ perft 4 449630 perft 5 10571176 perft 6 369603424 -id 1 +id 775 epd qbrkb1r1/ppp2ppp/3pn1n1/P3p3/4P3/3P4/1PP2PPP/QBRKBNRN w GCgc - 1 9 perft 1 26 perft 2 755 @@ -6984,7 +6985,7 @@ perft 4 604483 perft 5 17164382 perft 6 510878835 -id 1 +id 776 epd qrkbb1r1/ppp1pnpp/3p2n1/5p2/1P3P2/2Q3N1/P1PPP1PP/1RKBB1RN w GBgb - 0 9 perft 1 35 perft 2 918 @@ -6993,7 +6994,7 @@ perft 4 870888 perft 5 30933394 perft 6 867833733 -id 1 +id 777 epd qrknbbrn/ppp1ppp1/8/7p/2Bp4/4PPP1/PPPP3P/QRKNB1RN w GBgb - 0 9 perft 1 27 perft 2 593 @@ -7002,7 +7003,7 @@ perft 4 376808 perft 5 10422676 perft 6 258348640 -id 1 +id 778 epd qrk1brnb/ppppp3/4n2p/5pp1/2PP4/2N4P/PP2PPP1/QRK1BRNB w FBfb - 2 9 perft 1 24 perft 2 672 @@ -7011,7 +7012,7 @@ perft 4 506189 perft 5 13765777 perft 6 414930519 -id 1 +id 779 epd qbrknrb1/p2ppppp/2p3n1/8/p4P2/6PP/1PPPP3/QBRKNRBN w FCfc - 0 9 perft 1 29 perft 2 759 @@ -7020,7 +7021,7 @@ perft 4 634493 perft 5 20416668 perft 6 584870558 -id 1 +id 780 epd 1rkb1rbn/p1pp1ppp/3np3/1p6/4qP2/3NB3/PPPPPRPP/QRKB3N w Bfb - 0 9 perft 1 22 perft 2 923 @@ -7029,7 +7030,7 @@ perft 4 914106 perft 5 24049880 perft 6 957218571 -id 1 +id 781 epd 1rknrbbn/p1pp1p1p/8/1p2p1p1/4qPP1/2P5/PP1PP1BP/QRKNR1BN w EBeb - 0 9 perft 1 28 perft 2 1309 @@ -7038,7 +7039,7 @@ perft 4 1568968 perft 5 44576409 perft 6 1846382333 -id 1 +id 782 epd qrk1rn1b/ppppp2p/4n3/3b1pp1/4P2P/5BP1/PPPP1P2/QRKNRNB1 w EBeb - 3 9 perft 1 26 perft 2 839 @@ -7047,7 +7048,7 @@ perft 4 726354 perft 5 19978260 perft 6 661207281 -id 1 +id 783 epd bbrqk1rn/pp1ppppp/8/2p5/2P1P3/5n1P/PPBP1PP1/B1RQKNRN w GCgc - 1 9 perft 1 3 perft 2 95 @@ -7056,7 +7057,7 @@ perft 4 85038 perft 5 2518864 perft 6 80775549 -id 1 +id 784 epd brqbk2n/pppppprp/8/6p1/1P3n2/5P2/P1PPP1PP/R1QBKNRN w Gb - 2 9 perft 1 22 perft 2 593 @@ -7065,7 +7066,7 @@ perft 4 362760 perft 5 8922397 perft 6 253271592 -id 1 +id 785 epd brqknbr1/pp3ppp/3p2n1/2p1p3/2P5/5P2/PPKPP1PP/BRQ1NBRN w gb - 0 9 perft 1 21 perft 2 590 @@ -7074,7 +7075,7 @@ perft 4 397355 perft 5 9581695 perft 6 304103516 -id 1 +id 786 epd 1rqknrnb/2pp1ppp/p3p3/1p6/P2P4/5bP1/1PP1PP1P/BRQKNRNB w FBfb - 0 9 perft 1 24 perft 2 737 @@ -7083,7 +7084,7 @@ perft 4 598439 perft 5 17948681 perft 6 536330341 -id 1 +id 787 epd rbb1k1rn/p1pqpppp/6n1/1p1p4/5P2/3PP3/PPP1K1PP/RBBQ1NRN w ga - 3 9 perft 1 24 perft 2 694 @@ -7092,7 +7093,7 @@ perft 4 513782 perft 5 13094823 perft 6 419402704 -id 1 +id 788 epd rqbbknr1/1ppp2pp/p5n1/4pp2/P7/1PP5/1Q1PPPPP/R1BBKNRN w GAga - 0 9 perft 1 24 perft 2 600 @@ -7101,7 +7102,7 @@ perft 4 408207 perft 5 11029596 perft 6 308553169 -id 1 +id 789 epd rqbknbrn/2pppppp/6Q1/pp6/8/2P5/PP1PPPPP/R1BKNBRN w GAga - 2 9 perft 1 40 perft 2 949 @@ -7110,7 +7111,7 @@ perft 4 889887 perft 5 31296485 perft 6 881529007 -id 1 +id 790 epd rqbknr1b/pp1ppp2/2p2n1p/6p1/8/3P1PPP/PPP1P3/RQBKNRNB w FAfa - 0 9 perft 1 20 perft 2 560 @@ -7119,7 +7120,7 @@ perft 4 373921 perft 5 8687544 perft 6 277906201 -id 1 +id 791 epd rbqkbnrn/p3pppp/1p6/3p4/P1p3P1/1P6/1QPPPP1P/RB1KBNRN w GAga - 0 9 perft 1 30 perft 2 1155 @@ -7128,7 +7129,7 @@ perft 4 1351455 perft 5 43092716 perft 6 1614019629 -id 1 +id 792 epd rqkbb1rn/p1p1pppn/1p1p4/7p/4PP2/7P/PPPPB1P1/RQK1BNRN w GAga - 1 9 perft 1 30 perft 2 701 @@ -7137,7 +7138,7 @@ perft 4 515942 perft 5 15450970 perft 6 401499189 -id 1 +id 793 epd rqknbbrn/1p2pp1p/3p2p1/p1p5/P2P4/1P6/1KP1PPPP/RQ1NBBRN w ga - 0 9 perft 1 28 perft 2 756 @@ -7146,7 +7147,7 @@ perft 4 610320 perft 5 17989811 perft 6 525585996 -id 1 +id 794 epd rqknbrnb/1pp3pp/5p2/p2pp3/P7/3PPN2/1PP2PPP/RQKNBR1B w FAfa - 0 9 perft 1 26 perft 2 731 @@ -7155,7 +7156,7 @@ perft 4 550395 perft 5 15209404 perft 6 439767476 -id 1 +id 795 epd rbqkr1bn/p1pppp1p/1p1n4/6p1/7P/3P1PP1/PPP1P3/RBQKNRBN w FAa - 0 9 perft 1 27 perft 2 586 @@ -7164,7 +7165,7 @@ perft 4 381604 perft 5 10905865 perft 6 274364342 -id 1 +id 796 epd rqk1nrb1/ppbp1ppp/4p1n1/2p5/7P/1PP5/P2PPPP1/RQKBNRBN w FAfa - 1 9 perft 1 27 perft 2 749 @@ -7173,7 +7174,7 @@ perft 4 602318 perft 5 18084787 perft 6 520547029 -id 1 +id 797 epd rqknrbbn/pp1p1ppp/4p3/2p5/3P2P1/7P/PPP1PP2/RQKNRBBN w EAa - 0 9 perft 1 20 perft 2 533 @@ -7182,7 +7183,7 @@ perft 4 336248 perft 5 8230417 perft 6 245871540 -id 1 +id 798 epd rqknrnbb/pp1ppp1p/2p3p1/8/8/1P2P1NP/P1PP1PP1/RQKNR1BB w EAea - 0 9 perft 1 22 perft 2 633 @@ -7191,7 +7192,7 @@ perft 4 441877 perft 5 10827868 perft 6 343525739 -id 1 +id 799 epd 1brkq1rn/2pppppp/1p2n3/p2bN3/8/7P/PPPPPPP1/BBRKQ1RN w GCgc - 2 9 perft 1 27 perft 2 748 @@ -7200,7 +7201,7 @@ perft 4 580054 perft 5 16010135 perft 6 475206624 -id 1 +id 800 epd brkbqnrn/2pp1ppp/8/1p2p3/Pp2N3/8/2PPPPPP/BRKBQNR1 w GBgb - 0 9 perft 1 30 perft 2 827 @@ -7209,7 +7210,7 @@ perft 4 757837 perft 5 23746165 perft 6 751690068 -id 1 +id 801 epd brk1nbrn/pp1ppppp/2p5/7P/5P2/q2P4/PPP1P1P1/BRKQNBRN w GBgb - 1 9 perft 1 15 perft 2 471 @@ -7218,7 +7219,7 @@ perft 4 276424 perft 5 5960901 perft 6 190316951 -id 1 +id 802 epd brkqnrnb/1p1pp1p1/p4p2/2p4p/8/P2PP3/1PP1QPPP/BRK1NRNB w FBfb - 0 9 perft 1 24 perft 2 479 @@ -7227,7 +7228,7 @@ perft 4 280081 perft 5 7830230 perft 6 190419716 -id 1 +id 803 epd rbbkqnrn/2ppp2p/pp3p2/6p1/P6P/8/RPPPPPP1/1BBKQNRN w Gga - 0 9 perft 1 21 perft 2 523 @@ -7236,7 +7237,7 @@ perft 4 328733 perft 5 8322614 perft 6 242240658 -id 1 +id 804 epd rkbbqr1n/1ppppppn/7p/p7/4P3/2P2P2/PP1PB1PP/RKB1QNRN w GAa - 3 9 perft 1 27 perft 2 563 @@ -7245,7 +7246,7 @@ perft 4 372148 perft 5 11105151 perft 6 283211800 -id 1 +id 805 epd rkbqnbrn/ppppp3/8/5ppp/2P3P1/7P/PPQPPP2/RKB1NBRN w GAga - 0 9 perft 1 28 perft 2 639 @@ -7254,7 +7255,7 @@ perft 4 469250 perft 5 14872172 perft 6 384663405 -id 1 +id 806 epd rkb1nrnb/pppp1pp1/5q1p/8/P3p3/4R1P1/1PPPPP1P/1KBQNRNB w Ffa - 0 9 perft 1 28 perft 2 873 @@ -7263,7 +7264,7 @@ perft 4 720814 perft 5 20209424 perft 6 625281937 -id 1 +id 807 epd rbkqb1rn/1p1ppppp/4n3/p1p5/8/3PBP2/PPP1P1PP/RBKQ1NRN w GAga - 0 9 perft 1 26 perft 2 798 @@ -7272,7 +7273,7 @@ perft 4 667496 perft 5 18475618 perft 6 591681956 -id 1 +id 808 epd rk1qbnrn/1p1ppppp/1b6/p1p5/P7/2P3NP/1P1PPPP1/RKQBB1RN w GAga - 0 9 perft 1 22 perft 2 506 @@ -7281,7 +7282,7 @@ perft 4 301029 perft 5 7891676 perft 6 205739580 -id 1 +id 809 epd rk1nbbrn/ppp1ppp1/8/3p3p/1P1P2q1/5PB1/P1P1P1PP/RKQN1BRN w GAga - 1 9 perft 1 31 perft 2 956 @@ -7290,7 +7291,7 @@ perft 4 903799 perft 5 27827461 perft 6 876341492 -id 1 +id 810 epd rkqnbr1b/pp1pppp1/7p/2p2n2/P2P4/7N/RPP1PPPP/1KQNBR1B w Ffa - 0 9 perft 1 31 perft 2 750 @@ -7299,7 +7300,7 @@ perft 4 646252 perft 5 21639104 perft 6 617064197 -id 1 +id 811 epd rbkq1rbn/2p1pppp/pp3n2/3p4/5P2/3N2N1/PPPPP1PP/RBKQR1B1 w Afa - 2 9 perft 1 26 perft 2 647 @@ -7308,7 +7309,7 @@ perft 4 465119 perft 5 13643783 perft 6 369702807 -id 1 +id 812 epd rkqbr1bn/p2ppppp/1pp2n2/8/5P2/3P1N2/PPP1PRPP/RKQB2BN w Aa - 3 9 perft 1 24 perft 2 574 @@ -7317,7 +7318,7 @@ perft 4 371597 perft 5 10066892 perft 6 271121237 -id 1 +id 813 epd rk1qrbbn/p1ppp1pp/1p2n3/5p2/1P6/K3N3/P1PPPPPP/R1Q1RBBN w ea - 0 9 perft 1 25 perft 2 548 @@ -7326,7 +7327,7 @@ perft 4 340734 perft 5 9043111 perft 6 235545764 -id 1 +id 814 epd rkqnrnbb/pp1pp3/2p5/5ppp/8/PP4NP/2PPPPP1/RKQNR1BB w EAea - 0 9 perft 1 23 perft 2 727 @@ -7335,7 +7336,7 @@ perft 4 566572 perft 5 15078056 perft 6 471296844 -id 1 +id 815 epd bbrknq1r/ppppppp1/8/7p/5n2/3P4/PPP1PNPP/BBKRNQR1 w c - 0 9 perft 1 21 perft 2 610 @@ -7344,7 +7345,7 @@ perft 4 394705 perft 5 9605845 perft 6 293532398 -id 1 +id 816 epd brkbnqr1/2pppnpp/pp3p2/8/4PPPP/8/PPPP4/BRKBNQRN w GBgb - 1 9 perft 1 30 perft 2 757 @@ -7353,7 +7354,7 @@ perft 4 621332 perft 5 20360394 perft 6 548380577 -id 1 +id 817 epd brk1qb1n/ppppppr1/2n3pp/8/2P3P1/2N5/PP1PPP1P/BR1KQBRN w b - 1 9 perft 1 26 perft 2 570 @@ -7362,7 +7363,7 @@ perft 4 352883 perft 5 10081351 perft 6 242864559 -id 1 +id 818 epd brknq1nb/pp2prpp/8/2pP1p2/6P1/2N5/PPPP1P1P/BRK1QRNB w FBb - 1 9 perft 1 33 perft 2 830 @@ -7371,7 +7372,7 @@ perft 4 764915 perft 5 26262884 perft 6 765831403 -id 1 +id 819 epd rbbk1qrn/ppp1p1pp/5p2/3p1n2/7N/P7/1PPPPPPP/RBB1KQRN w ga - 0 9 perft 1 21 perft 2 562 @@ -7380,7 +7381,7 @@ perft 4 378883 perft 5 9520963 perft 6 290579255 -id 1 +id 820 epd rk1b1qrn/ppp1pppp/5n2/3pN3/P6P/7b/1PPPPPP1/RKBB1QRN w GAga - 4 9 perft 1 28 perft 2 677 @@ -7389,7 +7390,7 @@ perft 4 488740 perft 5 14354779 perft 6 383207197 -id 1 +id 821 epd rkbnqbrn/pp1ppp1p/2p5/6p1/P7/4P3/KPPPQPPP/R1BN1BRN w - - 3 9 perft 1 28 perft 2 585 @@ -7398,7 +7399,7 @@ perft 4 401483 perft 5 12574541 perft 6 310495538 -id 1 +id 822 epd rk1nqrnb/pbpppp2/1p4p1/7p/P7/5NP1/1PPPPPBP/RKBNQR2 w FAfa - 2 9 perft 1 26 perft 2 774 @@ -7407,7 +7408,7 @@ perft 4 645200 perft 5 19093408 perft 6 576325868 -id 1 +id 823 epd rbknb1rn/p1pp2pp/1p6/4pp2/1q3P1B/2N5/PPPPPNPP/RBK2QR1 w GAga - 2 9 perft 1 31 perft 2 1206 @@ -7416,7 +7417,7 @@ perft 4 1374158 perft 5 42849564 perft 6 1555711209 -id 1 +id 824 epd rk1bbqrn/pp1pp1pp/3n4/5p2/3p4/1PP5/PK2PPPP/R1NBBQRN w ga - 0 9 perft 1 21 perft 2 629 @@ -7425,7 +7426,7 @@ perft 4 429667 perft 5 10587910 perft 6 332632033 -id 1 +id 825 epd rknqbbr1/p1pp1pp1/1p4n1/4p2p/4P1P1/6RB/PPPP1P1P/RKNQB2N w Aga - 0 9 perft 1 27 perft 2 753 @@ -7434,7 +7435,7 @@ perft 4 593155 perft 5 17318772 perft 6 507563675 -id 1 +id 826 epd rknqbr1b/pppp1ppp/4p2n/8/1P3P2/4P3/P1PPN1PP/RKNQBR1B w FAfa - 2 9 perft 1 26 perft 2 623 @@ -7443,7 +7444,7 @@ perft 4 460663 perft 5 13389799 perft 6 383508368 -id 1 +id 827 epd r2kqrbn/bppppppp/2n5/p4B2/5P2/2P5/PP1PP1PP/1RKNQRBN w F - 2 9 perft 1 39 perft 2 1026 @@ -7452,7 +7453,7 @@ perft 4 1011922 perft 5 35946987 perft 6 992756232 -id 1 +id 828 epd rk1bqrb1/ppppppp1/1n6/7p/2P2P1n/4P1Q1/PP1P2PP/RKNB1RBN w FAfa - 0 9 perft 1 35 perft 2 760 @@ -7461,7 +7462,7 @@ perft 4 610557 perft 5 21014787 perft 6 536852043 -id 1 +id 829 epd rkq1rb1n/ppppp1pp/1n6/5p2/PPb2P2/8/1KPPP1PP/R1NQRBBN w ea - 1 9 perft 1 27 perft 2 754 @@ -7470,7 +7471,7 @@ perft 4 568788 perft 5 16461795 perft 6 448313956 -id 1 +id 830 epd rknqr2b/pppnp1pp/3p4/3b1p2/8/1N1P2N1/PPP1PPPP/RKQ1R1BB w EAea - 1 9 perft 1 27 perft 2 803 @@ -7479,7 +7480,7 @@ perft 4 700453 perft 5 21875031 perft 6 654754840 -id 1 +id 831 epd bbrknrqn/ppppp1pB/8/2P2p1p/8/5N2/PP1PPPPP/B1RK1RQN w FCfc - 0 9 perft 1 30 perft 2 799 @@ -7488,7 +7489,7 @@ perft 4 671112 perft 5 20532790 perft 6 603059376 -id 1 +id 832 epd brkbnrq1/1pppp1p1/6np/p4p2/4P3/1PP5/P1KP1PPP/BR1BNRQN w fb - 1 9 perft 1 27 perft 2 726 @@ -7497,7 +7498,7 @@ perft 4 555622 perft 5 15156662 perft 6 457601127 -id 1 +id 833 epd brknrbq1/1p1p1ppp/p3p1n1/2p5/8/1P1BPP2/P1PP2PP/BRKNR1QN w EBeb - 0 9 perft 1 36 perft 2 786 @@ -7506,7 +7507,7 @@ perft 4 655019 perft 5 22852433 perft 6 577223409 -id 1 +id 834 epd brknrqnb/p2ppp1p/2p5/1p6/3P2p1/P1P1N3/1P2PPPP/BRK1RQNB w EBeb - 0 9 perft 1 23 perft 2 649 @@ -7515,7 +7516,7 @@ perft 4 440504 perft 5 10687843 perft 6 320881984 -id 1 +id 835 epd rbbk1rqn/1ppppppp/3n4/p7/2P5/3N4/PP1PPPPP/RBB1KRQN w fa - 1 9 perft 1 20 perft 2 478 @@ -7524,7 +7525,7 @@ perft 4 275250 perft 5 7094988 perft 6 185488058 -id 1 +id 836 epd rkbbnrqn/p2p1ppp/1p2p3/8/P1p1P3/1BP5/1P1P1PPP/RKB1NRQN w FAfa - 0 9 perft 1 22 perft 2 570 @@ -7533,7 +7534,7 @@ perft 4 346811 perft 5 8671852 perft 6 229898448 -id 1 +id 837 epd rkb1rb1n/ppppppqp/8/2n3p1/2P1P1P1/8/PP1P1P1P/RKBNRBQN w EAea - 1 9 perft 1 23 perft 2 663 @@ -7542,7 +7543,7 @@ perft 4 490748 perft 5 12900485 perft 6 404944553 -id 1 +id 838 epd rkb1rqnb/pppp3p/2n3p1/4pp2/P2P3P/2P5/1P2PPP1/RKBNRQNB w EAea - 0 9 perft 1 25 perft 2 845 @@ -7551,7 +7552,7 @@ perft 4 741972 perft 5 20276176 perft 6 683290790 -id 1 +id 839 epd rbk1brqn/ppp1pppp/8/3p4/7P/1P4P1/2PPPP2/RBKNBRQN w FAfa - 0 9 perft 1 24 perft 2 526 @@ -7560,7 +7561,7 @@ perft 4 322175 perft 5 9054028 perft 6 222704171 -id 1 +id 840 epd rknbbrqn/pp3pp1/4p3/2pp3p/2P5/8/PPBPPPPP/RKN1BRQN w FAfa - 0 9 perft 1 26 perft 2 756 @@ -7569,7 +7570,7 @@ perft 4 559186 perft 5 14697705 perft 6 433719427 -id 1 +id 841 epd 1knrbbqn/rp1p1ppp/p3p3/2p5/8/5P1P/PPPPP1P1/RKNRBBQN w DAd - 0 9 perft 1 26 perft 2 539 @@ -7578,7 +7579,7 @@ perft 4 345070 perft 5 10223443 perft 6 248715580 -id 1 +id 842 epd rknr1qnb/ppp1p1pp/3p2b1/8/4p3/1P3P1P/P1PP2P1/RKNRBQNB w DAda - 0 9 perft 1 25 perft 2 701 @@ -7587,7 +7588,7 @@ perft 4 561369 perft 5 16047041 perft 6 496340789 -id 1 +id 843 epd rbk1r1bn/ppppp1pp/4n3/5p2/1P3P2/4N2P/PqPPP1P1/RBK1RQBN w EAea - 1 9 perft 1 2 perft 2 60 @@ -7596,7 +7597,7 @@ perft 4 41765 perft 5 1017864 perft 6 33183408 -id 1 +id 844 epd r1nbrqbn/k1ppp1pp/1p6/p4p2/2P5/6PQ/PP1PPP1P/RKNBR1BN w EA - 0 9 perft 1 27 perft 2 699 @@ -7605,7 +7606,7 @@ perft 4 561765 perft 5 17192121 perft 6 499247248 -id 1 +id 845 epd rknrqbbn/1pp1pp2/p5p1/3p3p/6P1/PN5P/1PPPPP2/RK1RQBBN w DAda - 0 9 perft 1 23 perft 2 611 @@ -7614,7 +7615,7 @@ perft 4 435927 perft 5 11917036 perft 6 352885930 -id 1 +id 846 epd rknrqn1b/p1pp1ppb/8/1p2p1Qp/3P4/3N4/PPP1PPPP/RK1R1NBB w DAda - 0 9 perft 1 45 perft 2 1170 @@ -7623,7 +7624,7 @@ perft 4 1320341 perft 5 52213677 perft 6 1500007485 -id 1 +id 847 epd bbkrnrnq/p2p1ppp/2p1p3/1p6/1P2Q3/6P1/P1PPPP1P/BBKRNRN1 w - - 0 9 perft 1 41 perft 2 1035 @@ -7632,7 +7633,7 @@ perft 4 1035610 perft 5 38555608 perft 6 1037686769 -id 1 +id 848 epd brkbnr2/1ppppp1p/7n/p5N1/P2q4/8/1PPPPPPP/BRKBNRQ1 w FBfb - 1 9 perft 1 22 perft 2 869 @@ -7641,7 +7642,7 @@ perft 4 679754 perft 5 16453359 perft 6 567287944 -id 1 +id 849 epd brknrbnq/p1ppppp1/1p6/7p/2PP4/5P2/PPK1P1PP/BR1NRBNQ w eb - 1 9 perft 1 23 perft 2 641 @@ -7650,7 +7651,7 @@ perft 4 422240 perft 5 10192718 perft 6 302864305 -id 1 +id 850 epd brk1r1qb/pp1ppnpp/2p2pn1/8/6N1/2N3P1/PPPPPP1P/BRK1R1QB w EBeb - 3 9 perft 1 32 perft 2 863 @@ -7659,7 +7660,7 @@ perft 4 773191 perft 5 25848794 perft 6 720443112 -id 1 +id 851 epd rbbk1rnq/pppp1pp1/4p2p/8/3P2n1/4BN1P/PPP1PPP1/RB1K1RNQ w FAfa - 3 9 perft 1 26 perft 2 628 @@ -7668,7 +7669,7 @@ perft 4 411995 perft 5 11237919 perft 6 300314373 -id 1 +id 852 epd rkbbnr1q/p1pppppp/5n2/1p5B/PP6/4P3/2PP1PPP/RKB1NRNQ w FAfa - 0 9 perft 1 30 perft 2 692 @@ -7677,7 +7678,7 @@ perft 4 519283 perft 5 16025428 perft 6 420887328 -id 1 +id 853 epd rkb1rbnq/1pppp1pp/5p2/p7/5n1P/1PN3P1/P1PPPP2/RKB1RBNQ w EAea - 0 9 perft 1 32 perft 2 825 @@ -7686,7 +7687,7 @@ perft 4 697251 perft 5 23593363 perft 6 622249676 -id 1 +id 854 epd rkbnrnqb/1ppp1p1p/p5p1/4p3/4P3/2N2P2/PPPP2PP/RKBR1NQB w Aea - 0 9 perft 1 24 perft 2 487 @@ -7695,7 +7696,7 @@ perft 4 301989 perft 5 8782713 perft 6 215787079 -id 1 +id 855 epd rbknbr1q/pppp2pp/4p3/5p1n/1P2P2N/8/P1PP1PPP/RBKNBR1Q w FAfa - 0 9 perft 1 23 perft 2 571 @@ -7704,7 +7705,7 @@ perft 4 365272 perft 5 9224232 perft 6 257288920 -id 1 +id 856 epd rknbb1nq/pppppr2/5pp1/7p/8/1N4P1/PPPPPP1P/RK1BBRNQ w FAa - 2 9 perft 1 26 perft 2 548 @@ -7713,7 +7714,7 @@ perft 4 350173 perft 5 10587626 perft 6 253006082 -id 1 +id 857 epd rknr1bnq/p2pp1pp/1p3p2/2p4b/6PP/2P2N2/PP1PPP2/RKNRBB1Q w DAda - 1 9 perft 1 25 perft 2 502 @@ -7722,7 +7723,7 @@ perft 4 279098 perft 5 7824941 perft 6 175766730 -id 1 +id 858 epd rknrb1qb/ppp1pppp/3p4/8/4P1nP/2P5/PPKP1PP1/R1NRBNQB w da - 1 9 perft 1 23 perft 2 643 @@ -7731,7 +7732,7 @@ perft 4 426616 perft 5 10507328 perft 6 312096061 -id 1 +id 859 epd rbk1rnbq/pppp1npp/4p3/5p2/4P1P1/7P/PPPP1P1N/RBKNR1BQ w EAea - 1 9 perft 1 24 perft 2 591 @@ -7740,7 +7741,7 @@ perft 4 376988 perft 5 10251465 perft 6 263574861 -id 1 +id 860 epd rknbrnb1/p1pppp1p/1p6/3N2p1/P3q1P1/8/1PPPPP1P/RKNBR1BQ w EAea - 1 9 perft 1 28 perft 2 948 @@ -7749,7 +7750,7 @@ perft 4 864588 perft 5 26241141 perft 6 812343987 -id 1 +id 861 epd rknrn1b1/ppppppqp/8/6p1/2P5/2P1BP2/PP2P1PP/RKNRNB1Q w DAda - 1 9 perft 1 31 perft 2 807 @@ -7758,7 +7759,7 @@ perft 4 672973 perft 5 20455205 perft 6 588518645 -id 1 +id 862 epd 1k1rnqbb/npppppp1/r7/p2B3p/5P2/1N4P1/PPPPP2P/RK1RNQB1 w DAd - 0 9 perft 1 40 perft 2 1122 @@ -7767,7 +7768,7 @@ perft 4 1249989 perft 5 48711073 perft 6 1412437357 -id 1 +id 863 epd bbqr1rkn/pp1ppppp/8/2p5/1P2P1n1/7N/P1PP1P1P/BBQRKR1N w FD - 0 9 perft 1 26 perft 2 841 @@ -7776,7 +7777,7 @@ perft 4 746711 perft 5 21328001 perft 6 705170410 -id 1 +id 864 epd bqkr1rnn/1ppp1ppp/p4b2/4p3/P7/3PP2N/1PP2PPP/BQRBKR1N w FC - 3 9 perft 1 24 perft 2 500 @@ -7785,7 +7786,7 @@ perft 4 293824 perft 5 7928916 perft 6 197806842 -id 1 +id 865 epd bqrkrbnn/1pp1ppp1/8/p6p/3p4/P3P2P/QPPP1PP1/B1RKRBNN w ECec - 0 9 perft 1 31 perft 2 592 @@ -7794,7 +7795,7 @@ perft 4 396423 perft 5 12607528 perft 6 298629240 -id 1 +id 866 epd bqkrrnnb/2p1pppp/p7/1P1p4/8/2R3P1/PP1PPP1P/BQ1KRNNB w E - 0 9 perft 1 42 perft 2 1124 @@ -7803,7 +7804,7 @@ perft 4 1276664 perft 5 50052573 perft 6 1483524894 -id 1 +id 867 epd qbbrkrn1/p1pppn1p/8/1p3Pp1/2P5/8/PP1PPP1P/QBBRKRNN w FDfd - 0 9 perft 1 21 perft 2 577 @@ -7812,7 +7813,7 @@ perft 4 392131 perft 5 9683808 perft 6 300294295 -id 1 +id 868 epd qrbbkrnn/pp1p2pp/4p3/5p2/2p2P1P/2P5/PP1PP1P1/QRBBKRNN w FBfb - 0 9 perft 1 21 perft 2 571 @@ -7821,7 +7822,7 @@ perft 4 345681 perft 5 8239872 perft 6 228837930 -id 1 +id 869 epd qrbkrbn1/1pp1pppp/p2p4/8/5PPn/2P5/PP1PP3/QRBKRBNN w EBeb - 0 9 perft 1 18 perft 2 466 @@ -7830,7 +7831,7 @@ perft 4 257776 perft 5 5679073 perft 6 162883949 -id 1 +id 870 epd qrb1rnnb/pp1p1ppp/2pk4/4p3/1P2P3/1R6/P1PP1PPP/Q1BKRNNB w E - 4 9 perft 1 37 perft 2 760 @@ -7839,7 +7840,7 @@ perft 4 562201 perft 5 19486022 perft 6 421740856 -id 1 +id 871 epd qbrkbrn1/p1pppp1p/6n1/1p4p1/1P6/5P2/P1PPPBPP/QBRK1RNN w FCfc - 1 9 perft 1 33 perft 2 824 @@ -7848,7 +7849,7 @@ perft 4 750924 perft 5 25176664 perft 6 734656217 -id 1 +id 872 epd qrkbbr2/2pppppp/5nn1/pp1Q4/P7/3P4/1PP1PPPP/1RKBBRNN w FBfb - 0 9 perft 1 42 perft 2 1147 @@ -7857,7 +7858,7 @@ perft 4 1311247 perft 5 48216013 perft 6 1522548864 -id 1 +id 873 epd qrkrbbnn/pp2pp2/2pp2pp/1B6/P7/4P3/1PPP1PPP/QRKRB1NN w DBdb - 0 9 perft 1 26 perft 2 464 @@ -7866,7 +7867,7 @@ perft 4 242892 perft 5 6928220 perft 6 142507795 -id 1 +id 874 epd qrkrbnnb/p1pp1pp1/1p5p/4p3/1P6/6PN/PKPPPP1P/QR1RBN1B w db - 0 9 perft 1 29 perft 2 705 @@ -7875,7 +7876,7 @@ perft 4 529810 perft 5 15055365 perft 6 419552571 -id 1 +id 875 epd qbrkr1bn/p1p1pp1p/1p1p2n1/6p1/3P1P2/4P3/PPP3PP/QBKRRNBN w ec - 2 9 perft 1 23 perft 2 613 @@ -7884,7 +7885,7 @@ perft 4 426484 perft 5 10747407 perft 6 323905533 -id 1 +id 876 epd qrk1rnb1/p1pp1ppp/1p2Bbn1/8/4P3/6P1/PPPP1P1P/QRK1RNBN w EBeb - 1 9 perft 1 28 perft 2 927 @@ -7893,7 +7894,7 @@ perft 4 846839 perft 5 23063284 perft 6 807913585 -id 1 +id 877 epd 1qkrnbbn/1rpppppp/pp6/5N2/P4P2/8/1PPPP1PP/QRKRNBB1 w DBd - 3 9 perft 1 30 perft 2 542 @@ -7902,7 +7903,7 @@ perft 4 345172 perft 5 10976745 perft 6 251694423 -id 1 +id 878 epd qrkr2bb/pppppppp/8/1n2n3/1N5P/1P6/P1PPPPP1/QRKR1NBB w DBdb - 1 9 perft 1 28 perft 2 719 @@ -7911,7 +7912,7 @@ perft 4 562015 perft 5 17351761 perft 6 479400272 -id 1 +id 879 epd bbrqkrnn/3ppppp/8/ppp5/6P1/4P2N/PPPPKP1P/BBRQ1R1N w fc - 0 9 perft 1 21 perft 2 704 @@ -7920,7 +7921,7 @@ perft 4 546215 perft 5 13676371 perft 6 470796854 -id 1 +id 880 epd brqbkrnn/1pp2p1p/3pp1p1/p5N1/8/1P6/P1PPPPPP/BRQBK1RN w Bfb - 0 9 perft 1 34 perft 2 688 @@ -7929,7 +7930,7 @@ perft 4 505618 perft 5 16639723 perft 6 402140795 -id 1 +id 881 epd br1krb1n/2qppppp/pp3n2/8/1P4P1/8/P1PPPP1P/1RQKRBNN w EBeb - 0 9 perft 1 24 perft 2 945 @@ -7938,7 +7939,7 @@ perft 4 926427 perft 5 25019636 perft 6 959651619 -id 1 +id 882 epd brqkr1nb/2ppp1pp/1p2np2/p7/2P1PN2/8/PP1P1PPP/BRQKRN1B w EBeb - 0 9 perft 1 28 perft 2 675 @@ -7947,7 +7948,7 @@ perft 4 504128 perft 5 15516491 perft 6 417396563 -id 1 +id 883 epd rbbqkrnn/3pppp1/p7/1pp4p/2P1P2P/8/PP1P1PP1/RBBQKRNN w FAfa - 0 9 perft 1 26 perft 2 671 @@ -7956,7 +7957,7 @@ perft 4 496806 perft 5 14072641 perft 6 404960259 -id 1 +id 884 epd rqbbkr1n/pp1p1p1p/4pn2/2p3p1/4P1P1/3P3P/PPP2P2/RQBBKRNN w FAfa - 0 9 perft 1 22 perft 2 633 @@ -7965,7 +7966,7 @@ perft 4 441809 perft 5 10776416 perft 6 335689685 -id 1 +id 885 epd rqbkrbnn/p1ppp3/1p3pp1/7p/3P4/P1P5/1PQ1PPPP/R1BKRBNN w EAea - 0 9 perft 1 32 perft 2 607 @@ -7974,7 +7975,7 @@ perft 4 454319 perft 5 15586203 perft 6 383515709 -id 1 +id 886 epd rqbkrnn1/pp2ppbp/3p4/2p3p1/2P5/1P3N1P/P2PPPP1/RQBKRN1B w EAea - 1 9 perft 1 29 perft 2 943 @@ -7983,7 +7984,7 @@ perft 4 908740 perft 5 28761841 perft 6 907579129 -id 1 +id 887 epd rbqkb1nn/1ppppr1p/p5p1/5p2/1P6/2P4P/P1KPPPP1/RBQ1BRNN w a - 1 9 perft 1 22 perft 2 441 @@ -7992,7 +7993,7 @@ perft 4 231273 perft 5 5784206 perft 6 140934555 -id 1 +id 888 epd rqkb1rnn/1pp1pp1p/p5p1/1b1p4/3P4/P5P1/RPP1PP1P/1QKBBRNN w Ffa - 1 9 perft 1 21 perft 2 505 @@ -8001,7 +8002,7 @@ perft 4 290897 perft 5 7147063 perft 6 188559137 -id 1 +id 889 epd rq1rbbnn/pkp1ppp1/3p3p/1p2N1P1/8/8/PPPPPP1P/RQKRBB1N w DA - 0 9 perft 1 27 perft 2 608 @@ -8010,7 +8011,7 @@ perft 4 387751 perft 5 10808908 perft 6 268393274 -id 1 +id 890 epd rqkrb2b/p2ppppp/2p3nn/1p6/5P2/PP1P4/2P1P1PP/RQKRBNNB w DAda - 1 9 perft 1 30 perft 2 749 @@ -8019,7 +8020,7 @@ perft 4 581531 perft 5 16916813 perft 6 485406712 -id 1 +id 891 epd rbqkr1bn/pp1ppp2/2p1n2p/6p1/8/4BPNP/PPPPP1P1/RBQKRN2 w EAea - 0 9 perft 1 23 perft 2 600 @@ -8028,7 +8029,7 @@ perft 4 410057 perft 5 11041820 perft 6 314327867 -id 1 +id 892 epd rqkbrnb1/2ppp1pp/pp3pn1/8/5P2/B2P4/PPP1P1PP/RQKBRN1N w EAea - 2 9 perft 1 22 perft 2 569 @@ -8037,7 +8038,7 @@ perft 4 371471 perft 5 9395816 perft 6 269460607 -id 1 +id 893 epd rqkrnbb1/p1p1pppp/1p4n1/3p4/7P/P3P3/1PPPBPP1/RQKRN1BN w DAda - 0 9 perft 1 27 perft 2 579 @@ -8046,7 +8047,7 @@ perft 4 373079 perft 5 10238486 perft 6 266047417 -id 1 +id 894 epd rqkrn1bb/p1ppp1pp/4n3/1p6/6p1/4N3/PPPPPPPP/RQKR2BB w DAda - 0 9 perft 1 20 perft 2 462 @@ -8055,7 +8056,7 @@ perft 4 274162 perft 5 6563859 perft 6 193376359 -id 1 +id 895 epd bbrkqr2/pppp1ppp/6nn/8/2P1p3/3PP2N/PP3PPP/BBRKQR1N w FCfc - 0 9 perft 1 28 perft 2 724 @@ -8064,7 +8065,7 @@ perft 4 619064 perft 5 19318355 perft 6 593204629 -id 1 +id 896 epd brk1qrnn/1pppbppp/4p3/8/1p6/P1P4P/3PPPP1/BRKBQRNN w FBfb - 1 9 perft 1 24 perft 2 662 @@ -8073,7 +8074,7 @@ perft 4 468215 perft 5 12610387 perft 6 355969349 -id 1 +id 897 epd 1r1qrbnn/p1pkpppp/1p1p4/8/3P1PP1/P4b2/1PP1P2P/BRKQRBNN w EB - 1 9 perft 1 22 perft 2 696 @@ -8082,7 +8083,7 @@ perft 4 510247 perft 5 13697382 perft 6 401903030 -id 1 +id 898 epd 1rkqrnnb/p1p1p1pp/1p1p4/3b1p1N/4P3/5N2/PPPP1PPP/BRKQR2B w EBeb - 1 9 perft 1 29 perft 2 887 @@ -8091,7 +8092,7 @@ perft 4 816176 perft 5 26051242 perft 6 791718847 -id 1 +id 899 epd rbbkq1rn/pppppppp/7n/8/P7/3P3P/1PPKPPP1/RBB1QRNN w a - 3 9 perft 1 22 perft 2 417 @@ -8100,7 +8101,7 @@ perft 4 216855 perft 5 5505063 perft 6 134818483 -id 1 +id 900 epd rkbbqr1n/1p1pppp1/2p2n2/p4NBp/8/3P4/PPP1PPPP/RK1BQRN1 w FAfa - 0 9 perft 1 37 perft 2 832 @@ -8109,7 +8110,7 @@ perft 4 728154 perft 5 26676373 perft 6 673756141 -id 1 +id 901 epd rkbqrb1n/3pBppp/ppp2n2/8/8/P2P4/1PP1PPPP/RK1QRBNN w EAea - 0 9 perft 1 28 perft 2 685 @@ -8118,7 +8119,7 @@ perft 4 543069 perft 5 16033316 perft 6 482288814 -id 1 +id 902 epd rkb1rn1b/ppppqppp/4p3/8/1P2n1P1/5Q2/P1PP1P1P/RKB1RNNB w EAea - 2 9 perft 1 37 perft 2 1158 @@ -8127,7 +8128,7 @@ perft 4 1234768 perft 5 44672979 perft 6 1389312729 -id 1 +id 903 epd r1kqbrnn/pp1pp1p1/7p/2P2p2/5b2/3P4/P1P1P1PP/RBKQBRNN w FAfa - 0 9 perft 1 5 perft 2 161 @@ -8136,7 +8137,7 @@ perft 4 154885 perft 5 4734999 perft 6 157499039 -id 1 +id 904 epd rkqbbr1n/ppp1ppp1/8/Q2p3p/4n3/3P1P2/PPP1P1PP/RK1BBRNN w FAfa - 2 9 perft 1 38 perft 2 1144 @@ -8145,7 +8146,7 @@ perft 4 1236877 perft 5 43832975 perft 6 1366087771 -id 1 +id 905 epd rkqrbbn1/p1ppppp1/Bp5p/8/P6n/2P1P3/1P1P1PPP/RKQRB1NN w DAda - 0 9 perft 1 28 perft 2 551 @@ -8154,7 +8155,7 @@ perft 4 350861 perft 5 9944107 perft 6 251179183 -id 1 +id 906 epd rkqrb1nb/1ppp1ppp/p7/4p3/5n2/3P2N1/PPPQPPPP/RK1RB1NB w DAda - 0 9 perft 1 26 perft 2 690 @@ -8163,7 +8164,7 @@ perft 4 513628 perft 5 15965907 perft 6 418191735 -id 1 +id 907 epd rbkqrnbn/pppp1p2/4p1p1/7p/7P/P2P4/BPP1PPP1/R1KQRNBN w EAea - 0 9 perft 1 27 perft 2 515 @@ -8172,7 +8173,7 @@ perft 4 309727 perft 5 8792550 perft 6 218658292 -id 1 +id 908 epd rkqbrnbn/pp1ppp2/8/2p3p1/P1P4p/5P2/1PKPP1PP/R1QBRNBN w ea - 0 9 perft 1 27 perft 2 627 @@ -8181,7 +8182,7 @@ perft 4 431101 perft 5 11978698 perft 6 328434174 -id 1 +id 909 epd rkqrnbbn/1p2pp1p/3p2p1/p1p5/P5PP/3N4/1PPPPP2/RKQR1BBN w DAda - 0 9 perft 1 23 perft 2 624 @@ -8190,7 +8191,7 @@ perft 4 451860 perft 5 11960861 perft 6 367311176 -id 1 +id 910 epd rk2rnbb/ppqppppp/2pn4/8/1P3P2/6P1/P1PPP1NP/RKQR1NBB w DAa - 1 9 perft 1 27 perft 2 727 @@ -8199,7 +8200,7 @@ perft 4 581003 perft 5 16633696 perft 6 505212747 -id 1 +id 911 epd b1krrqnn/pp1ppp1p/2p3p1/8/P3Pb1P/1P6/2PP1PP1/BBRKRQNN w EC - 0 9 perft 1 32 perft 2 943 @@ -8208,7 +8209,7 @@ perft 4 865229 perft 5 28672582 perft 6 800922511 -id 1 +id 912 epd 1rkbrqnn/p1pp1ppp/1p6/8/P2Pp3/8/1PPKPPQP/BR1BR1NN w eb - 0 9 perft 1 28 perft 2 916 @@ -8217,7 +8218,7 @@ perft 4 817624 perft 5 22840279 perft 6 759318058 -id 1 +id 913 epd brkrqb1n/1pppp1pp/p7/3n1p2/P5P1/3PP3/1PP2P1P/BRKRQBNN w DBdb - 0 9 perft 1 27 perft 2 669 @@ -8226,7 +8227,7 @@ perft 4 484259 perft 5 13956472 perft 6 380267099 -id 1 +id 914 epd brkrqnnb/3pppp1/1p6/p1p4p/2P3P1/6N1/PP1PPP1P/BRKRQ1NB w DBdb - 0 9 perft 1 29 perft 2 699 @@ -8235,7 +8236,7 @@ perft 4 512639 perft 5 15093909 perft 6 406594531 -id 1 +id 915 epd r1bkrq1n/pp2pppp/3b1n2/2pp2B1/6P1/3P1P2/PPP1P2P/RB1KRQNN w EAea - 2 9 perft 1 27 perft 2 835 @@ -8244,7 +8245,7 @@ perft 4 713550 perft 5 19867800 perft 6 631209313 -id 1 +id 916 epd rk1brq1n/p1p1pppp/3p1n2/1p3b2/4P3/2NQ4/PPPP1PPP/RKBBR2N w EAea - 4 9 perft 1 36 perft 2 1004 @@ -8253,7 +8254,7 @@ perft 4 979608 perft 5 35143142 perft 6 966310885 -id 1 +id 917 epd rkbrqbnn/1p2ppp1/B1p5/p2p3p/4P2P/8/PPPP1PP1/RKBRQ1NN w DAda - 0 9 perft 1 27 perft 2 748 @@ -8262,7 +8263,7 @@ perft 4 597819 perft 5 17597073 perft 6 515304215 -id 1 +id 918 epd rkbrqn1b/pp1pp1pp/2p2p2/5n2/8/2P2P2/PP1PP1PP/RKBRQ1NB w DAda - 0 9 perft 1 20 perft 2 479 @@ -8271,7 +8272,7 @@ perft 4 266446 perft 5 6253775 perft 6 167767913 -id 1 +id 919 epd rbkrbnn1/ppppp1pp/5q2/5p2/5P2/P3P2N/1PPP2PP/RBKRBQ1N w DAda - 3 9 perft 1 28 perft 2 947 @@ -8280,7 +8281,7 @@ perft 4 876068 perft 5 26007841 perft 6 838704143 -id 1 +id 920 epd rkr1bqnn/1ppp1p1p/p5p1/4p3/3PP2b/2P2P2/PP4PP/RKRBBQNN w CAca - 0 9 perft 1 31 perft 2 1004 @@ -8289,7 +8290,7 @@ perft 4 1006830 perft 5 32688124 perft 6 1024529879 -id 1 +id 921 epd rkrqbbnn/pppp3p/8/4ppp1/1PP4P/8/P2PPPP1/RKRQBBNN w CAca - 0 9 perft 1 24 perft 2 717 @@ -8298,7 +8299,7 @@ perft 4 564137 perft 5 15844525 perft 6 484884485 -id 1 +id 922 epd rkrqbn1b/pppp2pp/8/4pp2/1P1P2n1/5N2/P1P1PP1P/RKRQBN1B w CAca - 0 9 perft 1 25 perft 2 718 @@ -8307,7 +8308,7 @@ perft 4 587666 perft 5 17257753 perft 6 537354146 -id 1 +id 923 epd rbkrqnbn/p1p1ppp1/1p1p4/8/3PP2p/2PB4/PP3PPP/R1KRQNBN w DAda - 0 9 perft 1 30 perft 2 754 @@ -8316,7 +8317,7 @@ perft 4 611322 perft 5 19338246 perft 6 532603566 -id 1 +id 924 epd 1krbqnbn/1p2pppp/r1pp4/p7/8/1P1P2PP/P1P1PP2/RKRBQNBN w CAc - 0 9 perft 1 21 perft 2 566 @@ -8325,7 +8326,7 @@ perft 4 375128 perft 5 9700847 perft 6 279864836 -id 1 +id 925 epd rkrq1b2/pppppppb/3n2np/2N5/4P3/7P/PPPP1PP1/RKRQ1BBN w CAca - 1 9 perft 1 33 perft 2 654 @@ -8334,7 +8335,7 @@ perft 4 479678 perft 5 15990307 perft 6 382218272 -id 1 +id 926 epd rkr1nnbb/ppp2p1p/3p1qp1/4p3/P5P1/3PN3/1PP1PP1P/RKRQN1BB w CAca - 1 9 perft 1 28 perft 2 715 @@ -8343,7 +8344,7 @@ perft 4 555328 perft 5 16303092 perft 6 468666425 -id 1 +id 927 epd bbrkrnqn/1p1ppppp/8/8/p2pP3/PP6/2P2PPP/BBRKRNQN w ECec - 0 9 perft 1 24 perft 2 757 @@ -8352,7 +8353,7 @@ perft 4 603231 perft 5 15957628 perft 6 509307623 -id 1 +id 928 epd brkbrnqn/ppp2p2/4p3/P2p2pp/6P1/5P2/1PPPP2P/BRKBRNQN w EBeb - 0 9 perft 1 25 perft 2 548 @@ -8361,7 +8362,7 @@ perft 4 348259 perft 5 9688526 perft 6 247750144 -id 1 +id 929 epd brkr1bqn/1pppppp1/3n3p/1p6/P7/4P1P1/1PPP1P1P/BRKRN1QN w DBdb - 0 9 perft 1 19 perft 2 359 @@ -8370,7 +8371,7 @@ perft 4 157099 perft 5 3521652 perft 6 81787718 -id 1 +id 930 epd brkr1qnb/pppp2pp/2B1p3/5p2/2n5/6PP/PPPPPPN1/BRKR1QN1 w DBdb - 1 9 perft 1 27 perft 2 854 @@ -8379,7 +8380,7 @@ perft 4 741626 perft 5 20558538 perft 6 667089231 -id 1 +id 931 epd rbbkrnqn/p1p1p1pp/8/1p1p4/1P1Pp3/6N1/P1P2PPP/RBBKRNQ1 w EAea - 0 9 perft 1 28 perft 2 723 @@ -8388,7 +8389,7 @@ perft 4 514440 perft 5 14621108 perft 6 397454100 -id 1 +id 932 epd rkbbrn1n/pppppp2/5q1p/6p1/3P3P/4P3/PPP2PP1/RKBBRNQN w EAea - 1 9 perft 1 25 perft 2 741 @@ -8397,7 +8398,7 @@ perft 4 585198 perft 5 15605840 perft 6 485037906 -id 1 +id 933 epd rkbr1bq1/ppnppppp/6n1/2p5/2P1N2P/8/PP1PPPP1/RKBRNBQ1 w DAda - 3 9 perft 1 24 perft 2 547 @@ -8406,7 +8407,7 @@ perft 4 339497 perft 5 9410221 perft 6 234041078 -id 1 +id 934 epd 1kbrnqnb/r1ppppp1/8/pp5p/8/1P1NP3/P1PP1PPP/RKB1RQNB w Ad - 2 9 perft 1 26 perft 2 618 @@ -8415,7 +8416,7 @@ perft 4 442643 perft 5 13112297 perft 6 357030697 -id 1 +id 935 epd rbkrb1qn/1pp1ppp1/3pn2p/pP6/8/4N1P1/P1PPPP1P/RBKRB1QN w DAda - 0 9 perft 1 21 perft 2 544 @@ -8424,7 +8425,7 @@ perft 4 338832 perft 5 8381483 perft 6 236013157 -id 1 +id 936 epd rkrbbnqn/ppppp3/5p2/6pp/5PBP/4P3/PPPP2P1/RKR1BNQN w CAca - 0 9 perft 1 30 perft 2 891 @@ -8433,7 +8434,7 @@ perft 4 764356 perft 5 21894752 perft 6 669256602 -id 1 +id 937 epd rkr1bb1n/ppppp1pp/5p2/4n3/3QP3/5P2/RPPP2PP/1KRNBB1N w Cca - 1 9 perft 1 45 perft 2 1172 @@ -8442,7 +8443,7 @@ perft 4 1332060 perft 5 57856784 perft 6 1501852662 -id 1 +id 938 epd rkr1bqnb/pp1ppppp/8/2pN4/1P6/5N2/P1PPnPPP/RKR1BQ1B w CAca - 0 9 perft 1 28 perft 2 730 @@ -8451,7 +8452,7 @@ perft 4 559167 perft 5 16323242 perft 6 463032124 -id 1 +id 939 epd rbkrnqb1/2ppppp1/p5np/1p6/8/3N4/PPPPPPPP/RBKRQNB1 w DAda - 2 9 perft 1 20 perft 2 417 @@ -8460,7 +8461,7 @@ perft 4 217390 perft 5 5180716 perft 6 133936564 -id 1 +id 940 epd rkrbnqb1/p1pppnpp/5p2/1p6/2P5/1P1P1N2/P3PPPP/RKRB1QBN w CAca - 0 9 perft 1 25 perft 2 546 @@ -8469,7 +8470,7 @@ perft 4 330316 perft 5 8813781 perft 6 222026485 -id 1 +id 941 epd rkr1qbbn/ppppppp1/4n3/7p/8/P7/KPPPPPPP/R1RNQBBN w ca - 0 9 perft 1 22 perft 2 484 @@ -8478,7 +8479,7 @@ perft 4 267495 perft 5 6633319 perft 6 163291279 -id 1 +id 942 epd rkrnqnb1/1ppppp2/p5p1/7p/8/P1bPP3/1PP1QPPP/RKRN1NBB w CAca - 0 9 perft 1 22 perft 2 636 @@ -8487,7 +8488,7 @@ perft 4 441001 perft 5 11614241 perft 6 331083405 -id 1 +id 943 epd b2krn1q/p1rppppp/1Q3n2/2p1b3/1P4P1/8/P1PPPP1P/BBRKRNN1 w ECe - 3 9 perft 1 36 perft 2 1192 @@ -8496,7 +8497,7 @@ perft 4 1406795 perft 5 50382104 perft 6 1650202838 -id 1 +id 944 epd brkbrnn1/pp1pppp1/7q/2p5/6Pp/4P1NP/PPPP1P2/BRKBR1NQ w EBeb - 2 9 perft 1 30 perft 2 978 @@ -8505,7 +8506,7 @@ perft 4 942398 perft 5 29205057 perft 6 936568065 -id 1 +id 945 epd brkrnb1q/pp1p1ppp/2p1p3/5n2/1P6/5N1N/P1PPPPPP/BRKR1B1Q w DBdb - 1 9 perft 1 31 perft 2 897 @@ -8514,7 +8515,7 @@ perft 4 810187 perft 5 25423729 perft 6 755334868 -id 1 +id 946 epd brkr1nqb/pp1p1pp1/2pn3p/P3p3/4P3/6P1/1PPP1P1P/BRKRNNQB w DBdb - 0 9 perft 1 19 perft 2 382 @@ -8523,7 +8524,7 @@ perft 4 182292 perft 5 4232274 perft 6 103537333 -id 1 +id 947 epd r1bkrn1q/ppbppppp/5n2/2p5/3P4/P6N/1PP1PPPP/RBBKRNQ1 w EAea - 3 9 perft 1 27 perft 2 822 @@ -8532,7 +8533,7 @@ perft 4 678880 perft 5 19115128 perft 6 578210135 -id 1 +id 948 epd rkbbrnnq/pp2pppp/8/2pp4/P1P5/1P3P2/3PP1PP/RKBBRNNQ w EAea - 1 9 perft 1 23 perft 2 643 @@ -8541,7 +8542,7 @@ perft 4 442070 perft 5 11170489 perft 6 329615708 -id 1 +id 949 epd rkbr1b1q/p1pppppp/1p1n4/7n/5QP1/3N4/PPPPPP1P/RKBR1BN1 w DAda - 4 9 perft 1 37 perft 2 943 @@ -8550,7 +8551,7 @@ perft 4 880474 perft 5 31568111 perft 6 842265141 -id 1 +id 950 epd rkbr1nqb/pppp2np/8/4ppp1/1P6/6N1/P1PPPPPP/RKBRN1QB w DAda - 1 9 perft 1 23 perft 2 574 @@ -8559,7 +8560,7 @@ perft 4 362306 perft 5 9020291 perft 6 261247606 -id 1 +id 951 epd rbkr1nnq/p1p1pp1p/1p4p1/3p4/b3P3/4N3/PPPPNPPP/RBKRB1Q1 w DAda - 0 9 perft 1 26 perft 2 900 @@ -8568,7 +8569,7 @@ perft 4 805006 perft 5 21653203 perft 6 745802405 -id 1 +id 952 epd rkrbb1nq/p2pppp1/1p4n1/2p4p/3N4/4P1P1/PPPP1P1P/RKRBBN1Q w CAca - 0 9 perft 1 32 perft 2 697 @@ -8577,7 +8578,7 @@ perft 4 531121 perft 5 17150175 perft 6 441578567 -id 1 +id 953 epd rkrnbb1q/pp2pp1p/6pn/2pp4/2B1P2P/8/PPPP1PP1/RKRNB1NQ w CAca - 0 9 perft 1 28 perft 2 854 @@ -8586,7 +8587,7 @@ perft 4 755990 perft 5 21823412 perft 6 712787248 -id 1 +id 954 epd rk2bnqb/pprpppp1/4n2p/2p5/P7/3P2NP/1PP1PPP1/RKRNB1QB w CAa - 1 9 perft 1 26 perft 2 596 @@ -8595,7 +8596,7 @@ perft 4 414862 perft 5 11758184 perft 6 323043654 -id 1 +id 955 epd r1krnnbq/pp1ppp1p/6p1/2p5/2P5/P3P3/Rb1P1PPP/1BKRNNBQ w Dda - 0 9 perft 1 2 perft 2 61 @@ -8604,7 +8605,7 @@ perft 4 40072 perft 5 937188 perft 6 28753562 -id 1 +id 956 epd 1krbnnbq/1pp1p1pp/r7/p2p1p2/3PP3/2P3P1/PP3P1P/RKRBNNBQ w CAc - 0 9 perft 1 30 perft 2 953 @@ -8613,7 +8614,7 @@ perft 4 860530 perft 5 25531358 perft 6 787205262 -id 1 +id 957 epd rkr1nbbq/2ppp1pp/1pn5/p4p2/P6P/3P4/1PP1PPPB/RKRNNB1Q w CAca - 1 9 perft 1 24 perft 2 645 @@ -8622,7 +8623,7 @@ perft 4 446423 perft 5 11484012 perft 6 341262639 -id 1 +id 958 epd rkrnnqbb/p1ppp2p/Qp6/4Pp2/5p2/8/PPPP2PP/RKRNN1BB w CAca - 0 9 perft 1 35 perft 2 929 @@ -8631,7 +8632,7 @@ perft 4 896130 perft 5 31272517 perft 6 915268405 -id 1 +id 959 epd bbq1nr1r/pppppk1p/2n2p2/6p1/P4P2/4P1P1/1PPP3P/BBQNNRKR w HF - 1 9 perft 1 23 perft 2 589 From bc1c55aeaf619fd61e5116283705274e701df378 Mon Sep 17 00:00:00 2001 From: Jackson Hall Date: Thu, 26 Jan 2023 12:31:56 -0500 Subject: [PATCH 012/250] Update cp multiplier to match Lichess implementation --- chess/engine.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index f319d09bf..ca7f876ca 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -664,7 +664,9 @@ def _sf12_wins(cp: int, *, ply: int) -> int: return int(0.5 + 1000 / (1 + math.exp((a - x) / b))) def _lichess_raw_wins(cp: int) -> int: - return round(1000 / (1 + math.exp(-0.004 * cp))) + # https://github.com/lichess-org/lila/pull/11148 + # https://github.com/lichess-org/lila/blob/2242b0a08faa06e7be5508d338ede7bb09049777/modules/analyse/src/main/WinPercent.scala#L26-L30 + return round(1000 / (1 + math.exp(-0.00368208 * cp))) class Cp(Score): From b15d55e955d821a65d05416439e0d04c45be5d9a Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 2 Feb 2023 23:31:24 -0800 Subject: [PATCH 013/250] Send opponent information to Xboard engines --- chess/engine.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index ca7f876ca..cfdd58845 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1945,6 +1945,8 @@ def __init__(self) -> None: self.options = { "random": Option("random", "check", False, None, None, None), "computer": Option("computer", "check", False, None, None, None), + "name": Option("name", "string", "", None, None, None), + "rating": Option("rating", "string", "", None, None, None) } self.config: Dict[str, ConfigValue] = {} self.target_config: Dict[str, ConfigValue] = {} @@ -2055,7 +2057,7 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None # Set up starting position. root = board.root() - new_options = "random" in options or "computer" in options + new_options = any(param in options for param in ("random", "computer", "name", "rating")) new_game = self.first_game or self.game != game or new_options or root != self.board.root() self.game = game self.first_game = False @@ -2071,6 +2073,10 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None if self.config.get("random"): self.send_line("random") + if "name" in options and self.features.get("name", True): + self.send_line(f"name {options['name']}") + if "rating" in options: + self.send_line(f"rating {options['rating']}") if self.config.get("computer"): self.send_line("computer") @@ -2369,7 +2375,7 @@ def _setoption(self, name: str, value: ConfigValue) -> None: self.config[name] = value = option.parse(value) - if name in ["random", "computer"]: + if name in ["random", "computer", "name", "rating"]: # Applied in _new. pass elif name in ["memory", "cores"] or name.startswith("egtpath "): From 8a270859cab13537561998f1dbf601d9b0175e4c Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Fri, 3 Feb 2023 00:46:13 -0800 Subject: [PATCH 014/250] Use configure() method instead of play() --- chess/engine.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index cfdd58845..e91eaaba8 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2073,10 +2073,10 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None if self.config.get("random"): self.send_line("random") - if "name" in options and self.features.get("name", True): - self.send_line(f"name {options['name']}") - if "rating" in options: - self.send_line(f"rating {options['rating']}") + if "name" in self.config and self.features.get("name", True): + self.send_line(f"name {self.config['name']}") + if "rating" in self.config: + self.send_line(f"rating {self.config['rating']}") if self.config.get("computer"): self.send_line("computer") From 13be99744cbcb00480d08fb5582694c2a3e62469 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Fri, 3 Feb 2023 01:11:37 -0800 Subject: [PATCH 015/250] Fix failing tests --- chess/engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index e91eaaba8..68f54123c 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2073,9 +2073,9 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None if self.config.get("random"): self.send_line("random") - if "name" in self.config and self.features.get("name", True): + if self.config.get("name") and self.features.get("name", True): self.send_line(f"name {self.config['name']}") - if "rating" in self.config: + if self.config.get("rating"): self.send_line(f"rating {self.config['rating']}") if self.config.get("computer"): self.send_line("computer") From cb70c4db7f7fb8c49c759a2489d5c82412bb7691 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 4 Feb 2023 20:21:40 -0800 Subject: [PATCH 016/250] Separate rating inputs --- chess/engine.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 68f54123c..8f21f74ef 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1946,7 +1946,8 @@ def __init__(self) -> None: "random": Option("random", "check", False, None, None, None), "computer": Option("computer", "check", False, None, None, None), "name": Option("name", "string", "", None, None, None), - "rating": Option("rating", "string", "", None, None, None) + "engine_rating": Option("engine_rating", "spin", "", None, None, None), + "opponent_rating": Option("opponent_rating", "spin", "", None, None, None) } self.config: Dict[str, ConfigValue] = {} self.target_config: Dict[str, ConfigValue] = {} @@ -2057,7 +2058,7 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None # Set up starting position. root = board.root() - new_options = any(param in options for param in ("random", "computer", "name", "rating")) + new_options = any(param in options for param in ("random", "computer", "name", "engine_rating", "opponent_rating")) new_game = self.first_game or self.game != game or new_options or root != self.board.root() self.game = game self.first_game = False @@ -2075,8 +2076,8 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None self.send_line("random") if self.config.get("name") and self.features.get("name", True): self.send_line(f"name {self.config['name']}") - if self.config.get("rating"): - self.send_line(f"rating {self.config['rating']}") + if self.config.get("engine_rating") or self.config.get("opponent_rating"): + self.send_line(f"rating {self.config.get('engine_rating') or 0} {self.config.get('opponent_rating') or 0}") if self.config.get("computer"): self.send_line("computer") @@ -2375,7 +2376,7 @@ def _setoption(self, name: str, value: ConfigValue) -> None: self.config[name] = value = option.parse(value) - if name in ["random", "computer", "name", "rating"]: + if name in ["random", "computer", "name", "engine_rating", "opponent_rating"]: # Applied in _new. pass elif name in ["memory", "cores"] or name.startswith("egtpath "): From 7cf7dc15221925fe13e42cd279b035afdfa1cf94 Mon Sep 17 00:00:00 2001 From: disservin <45608332+Disservin@users.noreply.github.com> Date: Wed, 15 Feb 2023 21:14:18 +0100 Subject: [PATCH 017/250] strip option args --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index ca7f876ca..59455d503 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1377,7 +1377,7 @@ def _option(self, engine: UciProtocol, arg: str) -> None: current_var = None var = [] - for token in arg.split(" "): + for token in arg.strip().split(" "): if token == "name" and not name: current_parameter = "name" elif token == "type" and not type: From 5859dc20f01df7f862c06811a4d8206b76107cee Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 19 Feb 2023 20:58:01 -0800 Subject: [PATCH 018/250] Support implicit resigning from Xboard engines An XBoard engine is allowed to resign by putting the string "resign" somewhere in the comment of a "1-0" or "0-1" command. For example, "0-1 {White resigns}". Closes #964 --- chess/engine.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chess/engine.py b/chess/engine.py index ca7f876ca..8e5075fc5 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2197,6 +2197,8 @@ def line_received(self, engine: XBoardProtocol, line: str) -> None: self.play_result.resigned = True self._ping_after_move(engine) elif line.startswith("1-0") or line.startswith("0-1") or line.startswith("1/2-1/2"): + if "resign" in line and not self.result.done(): + self.play_result.resigned = True self._ping_after_move(engine) elif line.startswith("#"): pass From 47db69c6650bbc88109b5f0841fe87cc6a27a5b7 Mon Sep 17 00:00:00 2001 From: Joerg Sonnenberger Date: Fri, 24 Feb 2023 01:18:32 +0100 Subject: [PATCH 019/250] SVG output: add option for borders around board and diagram This is useful for printing when the margin is typically white to still give the visual clues about separation. Option defaults to off. Also slightly pad the coordinates at the top, so that "f" doesn't run into the outer border. --- chess/svg.py | 76 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index 6021e2054..d7aea03d9 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -76,6 +76,8 @@ "square dark lastmove": "#aaa23b", "square light lastmove": "#cdd16a", "margin": "#212121", + "inner border": "#111", + "outer border": "#111", "coord": "#e5e5e5", "arrow green": "#15781B80", "arrow red": "#88202080", @@ -245,7 +247,8 @@ def board(board: Optional[chess.BaseBoard] = None, *, coordinates: bool = True, colors: Dict[str, str] = {}, flipped: bool = False, - style: Optional[str] = None) -> str: + style: Optional[str] = None, + borders: bool = False) -> str: """ Renders a board with pieces and/or selected squares as an SVG image. @@ -267,11 +270,14 @@ def board(board: Optional[chess.BaseBoard] = None, *, :param coordinates: Pass ``False`` to disable the coordinate margin. :param colors: A dictionary to override default colors. Possible keys are ``square light``, ``square dark``, ``square light lastmove``, - ``square dark lastmove``, ``margin``, ``coord``, ``arrow green``, - ``arrow blue``, ``arrow red``, and ``arrow yellow``. Values should look - like ``#ffce9e`` (opaque), or ``#15781B80`` (transparent). + ``square dark lastmove``, ``margin``, ``coord``, ``inner border``, + ``outer border``, ``arrow green``, ``arrow blue``, ``arrow red``, + and ``arrow yellow``. Values should look like ``#ffce9e`` (opaque), + or ``#15781B80`` (transparent). :param flipped: Pass ``True`` to flip the board. :param style: A CSS stylesheet to include in the SVG image. + :param borders: Pass ``True`` to enable a border around the board and, + (if ``coordinates`` is enabled) the coordinate margin. >>> import chess >>> import chess.svg @@ -293,8 +299,11 @@ def board(board: Optional[chess.BaseBoard] = None, *, Use *orientation* with a color instead of the *flipped* toggle. """ orientation ^= flipped + inner_border = 1 if borders and coordinates else 0 + outer_border = 1 if borders else 0 margin = 15 if coordinates else 0 - svg = _svg(8 * SQUARE_SIZE + 2 * margin, size) + full_size = 2 * outer_border + 2 * margin + 2 * inner_border + 8 * SQUARE_SIZE + svg = _svg(full_size, size) if style: ET.SubElement(svg, "style").text = style @@ -318,34 +327,59 @@ def board(board: Optional[chess.BaseBoard] = None, *, if check is not None: defs.append(ET.fromstring(CHECK_GRADIENT)) - # Render coordinates. - if coordinates: - margin_color, margin_opacity = _select_color(colors, "margin") + if outer_border: + outer_border_color, outer_border_opacity = _select_color(colors, "outer border") ET.SubElement(svg, "rect", _attrs({ "x": 0, "y": 0, - "width": 2 * margin + 8 * SQUARE_SIZE, - "height": 2 * margin + 8 * SQUARE_SIZE, + "width": full_size, + "height": full_size, + "fill": outer_border_color, + "opacity": outer_border_opacity if outer_border_opacity < 1.0 else None, + })) + + if margin: + margin_color, margin_opacity = _select_color(colors, "margin") + ET.SubElement(svg, "rect", _attrs({ + "x": outer_border, + "y": outer_border, + "width": full_size - 2 * outer_border, + "height": full_size - 2 * outer_border, "fill": margin_color, "opacity": margin_opacity if margin_opacity < 1.0 else None, })) + + if inner_border: + inner_border_color, inner_border_opacity = _select_color(colors, "inner border") + ET.SubElement(svg, "rect", _attrs({ + "x": outer_border + margin, + "y": outer_border + margin, + "width": full_size - 2 * outer_border - 2 * margin, + "height": full_size - 2 * outer_border - 2 * margin, + "fill": inner_border_color, + "opacity": inner_border_opacity if inner_border_opacity < 1.0 else None, + })) + + # Render coordinates. + if coordinates: coord_color, coord_opacity = _select_color(colors, "coord") for file_index, file_name in enumerate(chess.FILE_NAMES): - x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin - svg.append(_coord(file_name, x, 0, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity)) - svg.append(_coord(file_name, x, margin + 8 * SQUARE_SIZE, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity)) + x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + inner_border + margin + outer_border + # Keep some padding here to separate the ascender from the border + svg.append(_coord(file_name, x, 1, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity)) + svg.append(_coord(file_name, x, full_size - outer_border - margin, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity)) for rank_index, rank_name in enumerate(chess.RANK_NAMES): - y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin + y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + inner_border + margin + outer_border svg.append(_coord(rank_name, 0, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity)) - svg.append(_coord(rank_name, margin + 8 * SQUARE_SIZE, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity)) + svg.append(_coord(rank_name, full_size - outer_border - margin, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity)) # Render board. for square, bb in enumerate(chess.BB_SQUARES): file_index = chess.square_file(square) rank_index = chess.square_rank(square) - x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin - y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin + x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + inner_border + margin + outer_border + y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + inner_border + margin + outer_border cls = ["square", "light" if chess.BB_LIGHT_SQUARES & bb else "dark"] if lastmove and square in [lastmove.from_square, lastmove.to_square]: @@ -442,10 +476,10 @@ def board(board: Optional[chess.BaseBoard] = None, *, head_file = chess.square_file(head) head_rank = chess.square_rank(head) - xtail = margin + (tail_file + 0.5 if orientation else 7.5 - tail_file) * SQUARE_SIZE - ytail = margin + (7.5 - tail_rank if orientation else tail_rank + 0.5) * SQUARE_SIZE - xhead = margin + (head_file + 0.5 if orientation else 7.5 - head_file) * SQUARE_SIZE - yhead = margin + (7.5 - head_rank if orientation else head_rank + 0.5) * SQUARE_SIZE + xtail = outer_border + margin + inner_border + (tail_file + 0.5 if orientation else 7.5 - tail_file) * SQUARE_SIZE + ytail = outer_border + margin + inner_border + (7.5 - tail_rank if orientation else tail_rank + 0.5) * SQUARE_SIZE + xhead = outer_border + margin + inner_border + (head_file + 0.5 if orientation else 7.5 - head_file) * SQUARE_SIZE + yhead = outer_border + margin + inner_border + (7.5 - head_rank if orientation else head_rank + 0.5) * SQUARE_SIZE if (head_file, head_rank) == (tail_file, tail_rank): ET.SubElement(svg, "circle", _attrs({ From 3439cb61bc632b7cb4087d512683f3abf75dfce3 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 24 Feb 2023 19:26:45 +0100 Subject: [PATCH 020/250] Tweak chess.svg.board(..., borders) docs --- chess/svg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index d7aea03d9..dbcbc5321 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -247,8 +247,8 @@ def board(board: Optional[chess.BaseBoard] = None, *, coordinates: bool = True, colors: Dict[str, str] = {}, flipped: bool = False, - style: Optional[str] = None, - borders: bool = False) -> str: + borders: bool = False, + style: Optional[str] = None) -> str: """ Renders a board with pieces and/or selected squares as an SVG image. @@ -275,9 +275,9 @@ def board(board: Optional[chess.BaseBoard] = None, *, and ``arrow yellow``. Values should look like ``#ffce9e`` (opaque), or ``#15781B80`` (transparent). :param flipped: Pass ``True`` to flip the board. - :param style: A CSS stylesheet to include in the SVG image. :param borders: Pass ``True`` to enable a border around the board and, - (if ``coordinates`` is enabled) the coordinate margin. + (if *coordinates* is enabled) the coordinate margin. + :param style: A CSS stylesheet to include in the SVG image. >>> import chess >>> import chess.svg From ac294570687fb38db448e010590ff7f7d3bb89ff Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 24 Feb 2023 20:23:17 +0100 Subject: [PATCH 021/250] Improve chess.pgn error logs (closes #961) --- chess/pgn.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 1a01b034e..8750443c5 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -872,12 +872,13 @@ def builder(cls: Type[GameT]) -> GameBuilder[GameT]: return GameBuilder(Game=cls) def __repr__(self) -> str: - return "<{} at {:#x} ({!r} vs. {!r}, {!r}{})>".format( + return "<{} at {:#x} ({!r} vs. {!r}, {!r} at {!r}{})>".format( type(self).__name__, id(self), self.headers.get("White", "?"), self.headers.get("Black", "?"), self.headers.get("Date", "????.??.??"), + self.headers.get("Site", "?"), f", {len(self.errors)} errors" if self.errors else "") @@ -1202,7 +1203,7 @@ def handle_error(self, error: Exception) -> None: >>> >>> game = chess.pgn.read_game(pgn, Visitor=MyGameBuilder) """ - LOGGER.exception("error during pgn parsing") + LOGGER.error("%s while parsing %r", error, self.game) self.game.errors.append(error) def result(self) -> GameT: From 7d0b189084a27136b2e04816fb6d70a37a2a7735 Mon Sep 17 00:00:00 2001 From: Joerg Sonnenberger Date: Sat, 25 Feb 2023 00:56:15 +0100 Subject: [PATCH 022/250] SVG: use a stroked rect for borders and margin This avoids painting the area under the squares. This makes it easier to use opacity for the field colors. --- chess/svg.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index dbcbc5321..008b0c87c 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -330,33 +330,39 @@ def board(board: Optional[chess.BaseBoard] = None, *, if outer_border: outer_border_color, outer_border_opacity = _select_color(colors, "outer border") ET.SubElement(svg, "rect", _attrs({ - "x": 0, - "y": 0, - "width": full_size, - "height": full_size, - "fill": outer_border_color, + "x": outer_border / 2, + "y": outer_border / 2, + "width": full_size - outer_border, + "height": full_size - outer_border, + "fill": "none", + "stroke": outer_border_color, + "stroke-width": outer_border, "opacity": outer_border_opacity if outer_border_opacity < 1.0 else None, })) if margin: margin_color, margin_opacity = _select_color(colors, "margin") ET.SubElement(svg, "rect", _attrs({ - "x": outer_border, - "y": outer_border, - "width": full_size - 2 * outer_border, - "height": full_size - 2 * outer_border, - "fill": margin_color, + "x": outer_border + margin / 2, + "y": outer_border + margin / 2, + "width": full_size - 2 * outer_border - margin, + "height": full_size - 2 * outer_border - margin, + "fill": "none", + "stroke": margin_color, + "stroke-width": margin, "opacity": margin_opacity if margin_opacity < 1.0 else None, })) if inner_border: inner_border_color, inner_border_opacity = _select_color(colors, "inner border") ET.SubElement(svg, "rect", _attrs({ - "x": outer_border + margin, - "y": outer_border + margin, - "width": full_size - 2 * outer_border - 2 * margin, - "height": full_size - 2 * outer_border - 2 * margin, - "fill": inner_border_color, + "x": outer_border + margin + inner_border / 2, + "y": outer_border + margin + inner_border / 2, + "width": full_size - 2 * outer_border - 2 * margin - inner_border, + "height": full_size - 2 * outer_border - 2 * margin - inner_border, + "fill": "none", + "stroke": inner_border_color, + "stroke-width": inner_border, "opacity": inner_border_opacity if inner_border_opacity < 1.0 else None, })) From d264559502ded8b6aa0bdaabd837f9e45f5a71b3 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 28 Feb 2023 00:14:55 -0800 Subject: [PATCH 023/250] Fix default values for rating configuration --- chess/engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 8f21f74ef..b7551598a 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1946,8 +1946,8 @@ def __init__(self) -> None: "random": Option("random", "check", False, None, None, None), "computer": Option("computer", "check", False, None, None, None), "name": Option("name", "string", "", None, None, None), - "engine_rating": Option("engine_rating", "spin", "", None, None, None), - "opponent_rating": Option("opponent_rating", "spin", "", None, None, None) + "engine_rating": Option("engine_rating", "spin", 0, None, None, None), + "opponent_rating": Option("opponent_rating", "spin", 0, None, None, None) } self.config: Dict[str, ConfigValue] = {} self.target_config: Dict[str, ConfigValue] = {} From fe199c799a01b37852ca2d3473f1af63b29b58f7 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 1 Mar 2023 02:58:23 -0800 Subject: [PATCH 024/250] Create unified API for sending opponent info Opponent information will be sent after "new" (for XBoard engines) or "ucinewgame" (for UCI engines). --- chess/engine.py | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index b7551598a..5ff66c6c0 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1121,6 +1121,19 @@ async def configure(self, options: ConfigMapping) -> None: (:func:`chess.engine.Option.is_managed()`). """ + @abc.abstractmethod + async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + """ + Sends the engine information about its opponent. The information will + be sent after a new game is announced and before the first move. + + :param opponent_name: Optional. The opponent's name. + :param opponent_rating: Optional. The opponent's ELO rating. + :param opponent_title: Optional. The opponent's title, such as GM, IM, and the like. + :param opponent_is_engine: Optional. Whether or not the opponent is another engine. + :param engine_rating: Optional. This engine's own rating. Only used by XBoard engines. + """ + @abc.abstractmethod async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> PlayResult: """ @@ -1435,6 +1448,9 @@ def _isready(self) -> None: def _ucinewgame(self) -> None: self.send_line("ucinewgame") + opponent_info = self.config.get("UCI_Opponent") + if opponent_info: + self.send_line(f"setoption name UCI_Opponent value {opponent_info}") self.first_game = False self.ponderhit = False @@ -1481,7 +1497,8 @@ def _setoption(self, name: str, value: ConfigValue) -> None: builder.append("value") builder.append(str(value)) - self.send_line(" ".join(builder)) + if name != "UCI_Opponent": # sent after ucinewgame + self.send_line(" ".join(builder)) self.config[name] = value def _configure(self, options: ConfigMapping) -> None: @@ -1500,6 +1517,13 @@ def start(self, engine: UciProtocol) -> None: return await self.communicate(UciConfigureCommand) + async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + if opponent_name and "UCI_Opponent" in self.options: + rating = opponent_rating or "none" + title = opponent_title or "none" + player_type = "computer" if opponent_is_engine else "human" + return await self.configure({"UCI_Opponent": f"{title} {rating} {player_type} {opponent_name}"}) + def _position(self, board: chess.Board) -> None: # Select UCI_Variant and UCI_Chess960. uci_variant = type(board).uci_variant @@ -2406,6 +2430,16 @@ def start(self, engine: XBoardProtocol) -> None: return await self.communicate(XBoardConfigureCommand) + async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[str] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[str] = None) -> None: + opponent_info = {"engine_rating": engine_rating or 0, + "opponent_rating": opponent_rating or 0, + "computer": opponent_is_engine} + + if self.features.get("name", True): + opponent_info["name"] = opponent_name + + return await self.configure(opponent_info) + async def quit(self) -> None: self.send_line("quit") await asyncio.shield(self.returncode) @@ -2789,6 +2823,14 @@ def configure(self, options: ConfigMapping) -> None: future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() + def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + with self._not_shut_down(): + coro = asyncio.wait_for( + self.protocol.send_opponent_information(opponent_name=opponent_name, opponent_rating=opponent_rating, opponent_title=opponent_title, opponent_is_engine=opponent_is_engine, engine_rating=engine_rating), + self.timeout) + future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) + return future.result + def ping(self) -> None: with self._not_shut_down(): coro = asyncio.wait_for(self.protocol.ping(), self.timeout) From b2b6163c724241a0c1c1d1dac8d94b8a31abb63c Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 1 Mar 2023 03:18:52 -0800 Subject: [PATCH 025/250] Fix errors found by mypy --- chess/engine.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 5ff66c6c0..967f8148b 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2430,12 +2430,12 @@ def start(self, engine: XBoardProtocol) -> None: return await self.communicate(XBoardConfigureCommand) - async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[str] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[str] = None) -> None: - opponent_info = {"engine_rating": engine_rating or 0, - "opponent_rating": opponent_rating or 0, - "computer": opponent_is_engine} + async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or 0, + "opponent_rating": opponent_rating or 0, + "computer": opponent_is_engine} - if self.features.get("name", True): + if opponent_name and self.features.get("name", True): opponent_info["name"] = opponent_name return await self.configure(opponent_info) @@ -2829,7 +2829,7 @@ def send_opponent_information(self, *, opponent_name: Optional[str] = None, oppo self.protocol.send_opponent_information(opponent_name=opponent_name, opponent_rating=opponent_rating, opponent_title=opponent_title, opponent_is_engine=opponent_is_engine, engine_rating=engine_rating), self.timeout) future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) - return future.result + return future.result() def ping(self) -> None: with self._not_shut_down(): From 1a642926f3d6d36d3518b0373abfd0fe0182c8f1 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 1 Mar 2023 03:51:48 -0800 Subject: [PATCH 026/250] Add title to opponent's name, if available --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 967f8148b..43d9cbcb7 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2436,7 +2436,7 @@ async def send_opponent_information(self, *, opponent_name: Optional[str] = None "computer": opponent_is_engine} if opponent_name and self.features.get("name", True): - opponent_info["name"] = opponent_name + opponent_info["name"] = f"{opponent_title or ''} {opponent_name}".strip() return await self.configure(opponent_info) From 69a5e0f6be881af449e05eba4d49f5b4a7123118 Mon Sep 17 00:00:00 2001 From: James Braza Date: Sat, 4 Mar 2023 13:07:05 -0800 Subject: [PATCH 027/250] Added clarity on SimpleEngine, module docstrings to code examples, and removed >>> from interpreter --- docs/engine.rst | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/docs/engine.rst b/docs/engine.rst index 979d0e915..4db5014c3 100644 --- a/docs/engine.rst +++ b/docs/engine.rst @@ -19,6 +19,7 @@ The preferred way to use the API is with an The examples also show a synchronous wrapper :class:`~chess.engine.SimpleEngine` that automatically spawns an event loop in the background. +:class:`~chess.engine.SimpleEngine` methods block until there is a result. Playing ------- @@ -27,6 +28,8 @@ Example: Let Stockfish play against itself, 100 milliseconds per move. .. code:: python + """Using synchronous engine.SimpleEngine.""" + import chess import chess.engine @@ -41,6 +44,8 @@ Example: Let Stockfish play against itself, 100 milliseconds per move. .. code:: python + """Using async engine.""" + import asyncio import chess import chess.engine @@ -74,6 +79,8 @@ Example: .. code:: python + """Using synchronous engine.SimpleEngine.""" + import chess import chess.engine @@ -93,6 +100,8 @@ Example: .. code:: python + """Using async engine.""" + import asyncio import chess import chess.engine @@ -139,6 +148,8 @@ Example: Stream information from the engine and stop on an arbitrary condition. .. code:: python + """Using synchronous engine.SimpleEngine.""" + import chess import chess.engine @@ -156,6 +167,8 @@ Example: Stream information from the engine and stop on an arbitrary condition. .. code:: python + """Using async engine.""" + import asyncio import chess import chess.engine @@ -193,21 +206,27 @@ Options :func:`~chess.Protocol.analyse()` and :func:`~chess.Protocol.analysis()` accept a dictionary of options. ->>> import chess.engine ->>> ->>> engine = chess.engine.SimpleEngine.popen_uci("/usr/bin/stockfish") ->>> ->>> # Check available options. ->>> engine.options["Hash"] -Option(name='Hash', type='spin', default=16, min=1, max=131072, var=[]) ->>> ->>> # Set an option. ->>> engine.configure({"Hash": 32}) ->>> ->>> # [...] +.. code:: python + + """Using synchronous engine.SimpleEngine.""" + + import chess.engine + + engine = chess.engine.SimpleEngine.popen_uci("/usr/bin/stockfish") + + # Check available options. + engine.options["Hash"] + # Option(name='Hash', type='spin', default=16, min=1, max=131072, var=[]) + + # Set an option. + engine.configure({"Hash": 32}) + + # [...] .. code:: python + """Using async engine.""" + import asyncio import chess.engine From 0192ebda9a733b25fd4c51ca7758b194c0f2516d Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 6 Mar 2023 21:11:38 +0100 Subject: [PATCH 028/250] Try code-block captions for #973 --- docs/engine.rst | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/docs/engine.rst b/docs/engine.rst index 4db5014c3..08f8f8f5e 100644 --- a/docs/engine.rst +++ b/docs/engine.rst @@ -26,9 +26,8 @@ Playing Example: Let Stockfish play against itself, 100 milliseconds per move. -.. code:: python - - """Using synchronous engine.SimpleEngine.""" +.. code-block:: python + :caption: Using synchronous :class:`~chess.engine.SimpleEngine` import chess import chess.engine @@ -42,9 +41,8 @@ Example: Let Stockfish play against itself, 100 milliseconds per move. engine.quit() -.. code:: python - - """Using async engine.""" +.. code-block:: python + :caption: Using asyncio import asyncio import chess @@ -77,9 +75,8 @@ Analysing and evaluating a position Example: -.. code:: python - - """Using synchronous engine.SimpleEngine.""" +.. code-block:: python + :caption: Using synchronous :class:`~chess.engine.SimpleEngine` import chess import chess.engine @@ -98,9 +95,8 @@ Example: engine.quit() -.. code:: python - - """Using async engine.""" +.. code-block:: python + :caption: Using asyncio import asyncio import chess @@ -146,9 +142,8 @@ Indefinite or infinite analysis Example: Stream information from the engine and stop on an arbitrary condition. -.. code:: python - - """Using synchronous engine.SimpleEngine.""" +.. code-block:: python + :caption: Using synchronous :class:`~chess.engine.SimpleEngine` import chess import chess.engine @@ -165,9 +160,8 @@ Example: Stream information from the engine and stop on an arbitrary condition. engine.quit() -.. code:: python - - """Using async engine.""" +.. code-block:: python + :caption: Using asyncio import asyncio import chess @@ -206,9 +200,8 @@ Options :func:`~chess.Protocol.analyse()` and :func:`~chess.Protocol.analysis()` accept a dictionary of options. -.. code:: python - - """Using synchronous engine.SimpleEngine.""" +.. code-block:: python + :caption: Using synchronous :class:`~chess.engine.SimpleEngine` import chess.engine @@ -223,9 +216,8 @@ Options # [...] -.. code:: python - - """Using async engine.""" +.. code-block:: python + :caption: Using asyncio import asyncio import chess.engine From c408d7c7107efad71ec46d6cec0c39569fd8f352 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 7 Mar 2023 20:11:32 -0800 Subject: [PATCH 029/250] Make Opponent class to store opponent information --- chess/engine.py | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 43d9cbcb7..4ec23941f 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -438,6 +438,15 @@ class Info(enum.IntFlag): INFO_ALL = Info.ALL +@dataclasses.dataclass +class Opponent: + """Used to store information about an engine's opponent.""" + name: Optional[str] + title: Optional[str] + rating: Optional[int] + is_engine = False + + class PovScore: """A relative :class:`~chess.engine.Score` and the point of view.""" @@ -1122,15 +1131,12 @@ async def configure(self, options: ConfigMapping) -> None: """ @abc.abstractmethod - async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: """ Sends the engine information about its opponent. The information will be sent after a new game is announced and before the first move. - :param opponent_name: Optional. The opponent's name. - :param opponent_rating: Optional. The opponent's ELO rating. - :param opponent_title: Optional. The opponent's title, such as GM, IM, and the like. - :param opponent_is_engine: Optional. Whether or not the opponent is another engine. + :param opponent: Optional. The opponent's information. :param engine_rating: Optional. This engine's own rating. Only used by XBoard engines. """ @@ -1517,12 +1523,12 @@ def start(self, engine: UciProtocol) -> None: return await self.communicate(UciConfigureCommand) - async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: - if opponent_name and "UCI_Opponent" in self.options: - rating = opponent_rating or "none" - title = opponent_title or "none" - player_type = "computer" if opponent_is_engine else "human" - return await self.configure({"UCI_Opponent": f"{title} {rating} {player_type} {opponent_name}"}) + async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + if opponent and opponent.name and "UCI_Opponent" in self.options: + rating = opponent.rating or "none" + title = opponent.title or "none" + player_type = "computer" if opponent.is_engine else "human" + return await self.configure({"UCI_Opponent": f"{title} {rating} {player_type} {opponent.name}"}) def _position(self, board: chess.Board) -> None: # Select UCI_Variant and UCI_Chess960. @@ -2430,13 +2436,16 @@ def start(self, engine: XBoardProtocol) -> None: return await self.communicate(XBoardConfigureCommand) - async def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + if opponent is None: + return + opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or 0, - "opponent_rating": opponent_rating or 0, - "computer": opponent_is_engine} + "opponent_rating": opponent.rating or 0, + "computer": opponent.is_engine} - if opponent_name and self.features.get("name", True): - opponent_info["name"] = f"{opponent_title or ''} {opponent_name}".strip() + if opponent.name and self.features.get("name", True): + opponent_info["name"] = f"{opponent.title or ''} {opponent.name}".strip() return await self.configure(opponent_info) @@ -2823,10 +2832,10 @@ def configure(self, options: ConfigMapping) -> None: future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() - def send_opponent_information(self, *, opponent_name: Optional[str] = None, opponent_rating: Optional[int] = None, opponent_title: Optional[str] = None, opponent_is_engine: bool = False, engine_rating: Optional[int] = None) -> None: + def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: with self._not_shut_down(): coro = asyncio.wait_for( - self.protocol.send_opponent_information(opponent_name=opponent_name, opponent_rating=opponent_rating, opponent_title=opponent_title, opponent_is_engine=opponent_is_engine, engine_rating=engine_rating), + self.protocol.send_opponent_information(opponent=opponent, engine_rating=engine_rating), self.timeout) future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() From dcdd7020956316ec69e519d461713eca81ae22c0 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 7 Mar 2023 20:38:43 -0800 Subject: [PATCH 030/250] Fix default argument and type --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 4ec23941f..feac6fc64 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -444,7 +444,7 @@ class Opponent: name: Optional[str] title: Optional[str] rating: Optional[int] - is_engine = False + is_engine: Optional[bool] class PovScore: From 49d31322dc24786de386565cfd94152e6e25884f Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 7 Mar 2023 20:47:01 -0800 Subject: [PATCH 031/250] Coerce entry to bool --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index feac6fc64..ba5c6ff88 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2442,7 +2442,7 @@ async def send_opponent_information(self, *, opponent: Optional[Opponent] = None opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or 0, "opponent_rating": opponent.rating or 0, - "computer": opponent.is_engine} + "computer": opponent.is_engine or False} if opponent.name and self.features.get("name", True): opponent_info["name"] = f"{opponent.title or ''} {opponent.name}".strip() From 1613a31cb74e9aeb2de140f9e5d9b096ee7a8cfa Mon Sep 17 00:00:00 2001 From: Trevor Bayless Date: Fri, 10 Mar 2023 08:40:06 -0600 Subject: [PATCH 032/250] Remove unused ponderhit code --- chess/engine.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 402252f83..d94bc028f 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1577,9 +1577,6 @@ def _go(self, limit: Limit, *, root_moves: Optional[Iterable[chess.Move]] = None self.send_line(" ".join(builder)) async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> PlayResult: - same_game = not self.first_game and game == self.game and not options - self.last_move = board.move_stack[-1] if (same_game and ponder and board.move_stack) else chess.Move.null() - class UciPlayCommand(BaseCommand[UciProtocol, PlayResult]): def __init__(self, engine: UciProtocol): super().__init__(engine) From 1f975c4000f91b1a54f368b3830641ab7e7ec159 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 13 Mar 2023 00:11:33 -0700 Subject: [PATCH 033/250] Add opponent information to play() method --- chess/engine.py | 61 +++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index ba5c6ff88..2545b6ea8 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1141,7 +1141,7 @@ async def send_opponent_information(self, *, opponent: Optional[Opponent] = None """ @abc.abstractmethod - async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> PlayResult: + async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}, opponent: Optional[Opponent] = None) -> PlayResult: """ Plays a position. @@ -1167,6 +1167,10 @@ async def play(self, board: chess.Board, limit: Limit, *, game: object = None, i analysis. The previous configuration will be restored after the analysis is complete. You can permanently apply a configuration with :func:`~chess.engine.Protocol.configure()`. + :param opponent: Optional. Information about a new opponent. Information + about the original opponent will be restored once the move is + complete. New opponent information can be made permanent with + :func:`~chess.engine.Protocol.send_opponent_information()`. """ @typing.overload @@ -1452,9 +1456,9 @@ def _id(self, engine: UciProtocol, arg: str) -> None: def _isready(self) -> None: self.send_line("isready") - def _ucinewgame(self) -> None: + def _ucinewgame(self, *, opponent: Optional[Opponent] = None) -> None: self.send_line("ucinewgame") - opponent_info = self.config.get("UCI_Opponent") + opponent_info = self._opponent_configuration(opponent=opponent).get("UCI_Opponent") or self.config.get("UCI_Opponent") if opponent_info: self.send_line(f"setoption name UCI_Opponent value {opponent_info}") self.first_game = False @@ -1523,12 +1527,17 @@ def start(self, engine: UciProtocol) -> None: return await self.communicate(UciConfigureCommand) - async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> ConfigMapping: if opponent and opponent.name and "UCI_Opponent" in self.options: rating = opponent.rating or "none" title = opponent.title or "none" player_type = "computer" if opponent.is_engine else "human" - return await self.configure({"UCI_Opponent": f"{title} {rating} {player_type} {opponent.name}"}) + return {"UCI_Opponent": f"{title} {rating} {player_type} {opponent.name}"} + else: + return {} + + async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) def _position(self, board: chess.Board) -> None: # Select UCI_Variant and UCI_Chess960. @@ -1606,7 +1615,7 @@ def _go(self, limit: Limit, *, root_moves: Optional[Iterable[chess.Move]] = None builder.append("0000") self.send_line(" ".join(builder)) - async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> PlayResult: + async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}, opponent: Optional[Opponent] = None) -> PlayResult: same_game = not self.first_game and game == self.game and not options self.last_move = board.move_stack[-1] if (same_game and ponder and board.move_stack) else chess.Move.null() @@ -1639,9 +1648,9 @@ def start(self, engine: UciProtocol) -> None: engine._configure(options) - if engine.first_game or engine.game != game: + if engine.first_game or engine.game != game or opponent: engine.game = game - engine._ucinewgame() + engine._ucinewgame(opponent=opponent) self.sent_isready = True engine._isready() else: @@ -2083,13 +2092,13 @@ def _variant(self, variant: Optional[str]) -> None: self.send_line(f"variant {variant}") - def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None: + def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponent: Optional[Opponent] = None) -> None: self._configure(options) # Set up starting position. root = board.root() new_options = any(param in options for param in ("random", "computer", "name", "engine_rating", "opponent_rating")) - new_game = self.first_game or self.game != game or new_options or root != self.board.root() + new_game = self.first_game or self.game != game or new_options or opponent or root != self.board.root() self.game = game self.first_game = False if new_game: @@ -2104,11 +2113,16 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping) -> None if self.config.get("random"): self.send_line("random") - if self.config.get("name") and self.features.get("name", True): + + opponent_name = (opponent.name if opponent else None) or self.config.get("name") + if opponent_name and self.features.get("name", True): self.send_line(f"name {self.config['name']}") - if self.config.get("engine_rating") or self.config.get("opponent_rating"): - self.send_line(f"rating {self.config.get('engine_rating') or 0} {self.config.get('opponent_rating') or 0}") - if self.config.get("computer"): + + opponent_rating = (opponent.rating if opponent else None) or self.config.get("opponent_rating") or 0 + if self.config.get("engine_rating") or opponent_rating: + self.send_line(f"rating {self.config.get('engine_rating') or 0} {opponent_rating}") + + if (opponent and opponent.is_engine) or self.config.get("computer"): self.send_line("computer") self.send_line("force") @@ -2162,7 +2176,7 @@ def line_received(self, engine: XBoardProtocol, line: str) -> None: return await self.communicate(XBoardPingCommand) - async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> PlayResult: + async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}, opponent: Optional[Opponent] = None) -> PlayResult: if root_moves is not None: raise EngineError("play with root_moves, but xboard supports 'include' only in analysis mode") @@ -2174,7 +2188,7 @@ def start(self, engine: XBoardProtocol) -> None: self.pong_after_ponder: Optional[str] = None # Set game, position and configure. - engine._new(board, game, options) + engine._new(board, game, options, opponent) # Limit or time control. clock = limit.white_clock if board.turn else limit.black_clock @@ -2436,9 +2450,9 @@ def start(self, engine: XBoardProtocol) -> None: return await self.communicate(XBoardConfigureCommand) - async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> ConfigMapping: if opponent is None: - return + return {} opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or 0, "opponent_rating": opponent.rating or 0, @@ -2446,8 +2460,11 @@ async def send_opponent_information(self, *, opponent: Optional[Opponent] = None if opponent.name and self.features.get("name", True): opponent_info["name"] = f"{opponent.title or ''} {opponent.name}".strip() - - return await self.configure(opponent_info) + + return opponent_info + + async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) async def quit(self) -> None: self.send_line("quit") @@ -2846,10 +2863,10 @@ def ping(self) -> None: future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() - def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> PlayResult: + def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}, opponent: Optional[Opponent] = None) -> PlayResult: with self._not_shut_down(): coro = asyncio.wait_for( - self.protocol.play(board, limit, game=game, info=info, ponder=ponder, draw_offered=draw_offered, root_moves=root_moves, options=options), + self.protocol.play(board, limit, game=game, info=info, ponder=ponder, draw_offered=draw_offered, root_moves=root_moves, options=options, opponent=opponent), self._timeout_for(limit)) future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() From f24517d23e4183ae12b373be267105335250cfad Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 15 Mar 2023 02:15:03 -0700 Subject: [PATCH 034/250] Add tests for play() method with opponent Requires that opponent information is always and only sent after a ucinewgame message. Specifying a new opponent in the play() method results in a new game starting. --- test.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test.py b/test.py index 29ea02749..a9dd5d89b 100755 --- a/test.py +++ b/test.py @@ -3271,13 +3271,18 @@ async def main(): mock.expect("uci", [ "option name Hash type spin default 16 min 1 max 33554432", "option name Ponder type check default false", + "option name UCI_Opponent type string", "uciok", ]) await protocol.initialize() + primary_opponent = chess.engine.Opponent("Eliza", None, 3500, True) + await protocol.send_opponent_information(opponent=primary_opponent) + # First search. mock.expect("setoption name Ponder value true") mock.expect("ucinewgame") + mock.expect("setoption name UCI_Opponent value none 3500 computer Eliza") mock.expect("isready", ["readyok"]) mock.expect("position startpos") mock.expect("go movetime 1000", ["bestmove d2d4 ponder g8f6"]) @@ -3341,6 +3346,33 @@ async def main(): mock.expect("go ponder movetime 5000") await protocol.play(board, chess.engine.Limit(time=5), ponder=True) + # Ponderhit prevented by new opponent, which starts a new game. + board.push(chess.Move.from_uci("c4d5")) + board.push(chess.Move.from_uci("e6d5")) + mock.expect("stop", ["bestmove c1g5 ponder h7h6"]) + mock.expect("ucinewgame") + mock.expect("setoption name UCI_Opponent value GM 3000 human Guy Chapman") + mock.expect("isready", ["readyok"]) + mock.expect("position startpos moves d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 d1c2 d7d5 c4d5 e6d5") + mock.expect("go movetime 5000", ["bestmove c1g5 ponder h7h6"]) + mock.expect("position startpos moves d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 d1c2 d7d5 c4d5 e6d5 c1g5 h7h6") + mock.expect("go ponder movetime 5000") + opponent = chess.engine.Opponent("Guy Chapman", "GM", 3000, False) + await protocol.play(board, chess.engine.Limit(time=5), ponder=True, opponent=opponent) + + # Ponderhit prevented by restoration of previous opponent, which again starts a new game. + board.push(chess.Move.from_uci("c1g5")) + board.push(chess.Move.from_uci("h7h6")) + mock.expect("stop", ["bestmove g5h4 ponder b8c6"]) + mock.expect("ucinewgame") + mock.expect("setoption name UCI_Opponent value none 3500 computer Eliza") + mock.expect("isready", ["readyok"]) + mock.expect("position startpos moves d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 d1c2 d7d5 c4d5 e6d5 c1g5 h7h6") + mock.expect("go movetime 5000", ["bestmove g5h4 ponder b8c6"]) + mock.expect("position startpos moves d2d4 g8f6 c2c4 e7e6 b1c3 f8b4 d1c2 d7d5 c4d5 e6d5 c1g5 h7h6 g5h4 b8c6") + mock.expect("go ponder movetime 5000") + await protocol.play(board, chess.engine.Limit(time=5), ponder=True) + mock.assert_done() asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) From 881160ead51d3a2e6b78b747768b7a5aa047fb9a Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 15 Mar 2023 02:17:06 -0700 Subject: [PATCH 035/250] Conform play() method with opponent to test If the opponent is changed through the play method, a new game is started with the current board position. This includes a blank opponent that follows an opponent specification on a previous move. --- chess/engine.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 149b3ff21..04899790b 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1369,6 +1369,8 @@ def __init__(self) -> None: self.first_game = True self.may_ponderhit: Optional[chess.Board] = None self.ponderhit = False + self.opponent: Optional[Opponent] = None + self.play_opponent: Optional[Opponent] = None async def initialize(self) -> None: class UciInitializeCommand(BaseCommand[UciProtocol, None]): @@ -1456,11 +1458,23 @@ def _id(self, engine: UciProtocol, arg: str) -> None: def _isready(self) -> None: self.send_line("isready") - def _ucinewgame(self, *, opponent: Optional[Opponent] = None) -> None: - self.send_line("ucinewgame") - opponent_info = self._opponent_configuration(opponent=opponent).get("UCI_Opponent") or self.config.get("UCI_Opponent") + def _opponent_changed(self, opponent: Optional[Opponent]) -> bool: + if self.play_opponent: + return opponent != self.play_opponent + elif opponent: + return opponent != self.opponent + + return False + + def _opponent_info(self) -> None: + opponent = self.play_opponent or self.opponent + opponent_info = self._opponent_configuration(opponent=opponent).get("UCI_Opponent") if opponent_info: self.send_line(f"setoption name UCI_Opponent value {opponent_info}") + + def _ucinewgame(self) -> None: + self.send_line("ucinewgame") + self._opponent_info() self.first_game = False self.ponderhit = False @@ -1537,6 +1551,7 @@ def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine return {} async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: + self.opponent = opponent return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) def _position(self, board: chess.Board) -> None: @@ -1623,7 +1638,7 @@ def __init__(self, engine: UciProtocol): # May ponderhit only in the same game and with unchanged target # options. The managed options UCI_AnalyseMode, Ponder, and # MultiPV never change between pondering play commands. - engine.may_ponderhit = board if ponder and not engine.first_game and game == engine.game and not engine._changed_options(options) else None + engine.may_ponderhit = board if ponder and not engine.first_game and game == engine.game and not engine._changed_options(options) and not engine._opponent_changed(opponent) else None def start(self, engine: UciProtocol) -> None: self.info: InfoDict = {} @@ -1645,9 +1660,10 @@ def start(self, engine: UciProtocol) -> None: engine._configure(options) - if engine.first_game or engine.game != game or opponent: + if engine.first_game or engine.game != game or engine._opponent_changed(opponent): engine.game = game - engine._ucinewgame(opponent=opponent) + engine.play_opponent = opponent + engine._ucinewgame() self.sent_isready = True engine._isready() else: From 35beb1f226a2adc8751859275d7c2775d82840c8 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 15 Mar 2023 02:20:40 -0700 Subject: [PATCH 036/250] Update send_opponent_information() docstring --- chess/engine.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 04899790b..b0486bf48 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1134,7 +1134,9 @@ async def configure(self, options: ConfigMapping) -> None: async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: """ Sends the engine information about its opponent. The information will - be sent after a new game is announced and before the first move. + be sent after a new game is announced and before the first move. This + method should be called before the first move of a game--i.e., the + first call to :func:`chess.engine.Protocol.play()`. :param opponent: Optional. The opponent's information. :param engine_rating: Optional. This engine's own rating. Only used by XBoard engines. From 7a5f82ae250a953b42b78886f3e71a13c99f9f00 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 15 Mar 2023 23:08:49 -0700 Subject: [PATCH 037/250] Use Protocol.config to update opponent Instead of having separate members of the UciProtocol class incorporate new opponent information into the config argument to simplify code. --- chess/engine.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index b0486bf48..5fe95f960 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1371,8 +1371,6 @@ def __init__(self) -> None: self.first_game = True self.may_ponderhit: Optional[chess.Board] = None self.ponderhit = False - self.opponent: Optional[Opponent] = None - self.play_opponent: Optional[Opponent] = None async def initialize(self) -> None: class UciInitializeCommand(BaseCommand[UciProtocol, None]): @@ -1460,17 +1458,8 @@ def _id(self, engine: UciProtocol, arg: str) -> None: def _isready(self) -> None: self.send_line("isready") - def _opponent_changed(self, opponent: Optional[Opponent]) -> bool: - if self.play_opponent: - return opponent != self.play_opponent - elif opponent: - return opponent != self.opponent - - return False - def _opponent_info(self) -> None: - opponent = self.play_opponent or self.opponent - opponent_info = self._opponent_configuration(opponent=opponent).get("UCI_Opponent") + opponent_info = self.config.get("UCI_Opponent") or self.target_config.get("UCI_Opponent") if opponent_info: self.send_line(f"setoption name UCI_Opponent value {opponent_info}") @@ -1553,7 +1542,6 @@ def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine return {} async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: - self.opponent = opponent return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) def _position(self, board: chess.Board) -> None: @@ -1633,6 +1621,11 @@ def _go(self, limit: Limit, *, root_moves: Optional[Iterable[chess.Move]] = None self.send_line(" ".join(builder)) async def play(self, board: chess.Board, limit: Limit, *, game: object = None, info: Info = INFO_NONE, ponder: bool = False, draw_offered: bool = False, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}, opponent: Optional[Opponent] = None) -> PlayResult: + new_options: Dict[str, ConfigValue] = {} + for name, value in options.items(): + new_options[name] = value + new_options.update(self._opponent_configuration(opponent=opponent)) + class UciPlayCommand(BaseCommand[UciProtocol, PlayResult]): def __init__(self, engine: UciProtocol): super().__init__(engine) @@ -1640,7 +1633,7 @@ def __init__(self, engine: UciProtocol): # May ponderhit only in the same game and with unchanged target # options. The managed options UCI_AnalyseMode, Ponder, and # MultiPV never change between pondering play commands. - engine.may_ponderhit = board if ponder and not engine.first_game and game == engine.game and not engine._changed_options(options) and not engine._opponent_changed(opponent) else None + engine.may_ponderhit = board if ponder and not engine.first_game and game == engine.game and not engine._changed_options(new_options) else None def start(self, engine: UciProtocol) -> None: self.info: InfoDict = {} @@ -1653,18 +1646,19 @@ def start(self, engine: UciProtocol) -> None: engine.send_line("ponderhit") return - if "UCI_AnalyseMode" in engine.options and "UCI_AnalyseMode" not in engine.target_config and all(name.lower() != "uci_analysemode" for name in options): + if "UCI_AnalyseMode" in engine.options and "UCI_AnalyseMode" not in engine.target_config and all(name.lower() != "uci_analysemode" for name in new_options): engine._setoption("UCI_AnalyseMode", False) if "Ponder" in engine.options: engine._setoption("Ponder", ponder) if "MultiPV" in engine.options: engine._setoption("MultiPV", engine.options["MultiPV"].default) - engine._configure(options) + new_opponent = new_options.get("UCI_Opponent") or engine.target_config.get("UCI_Opponent") + opponent_changed = new_opponent != engine.config.get("UCI_Opponent") + engine._configure(new_options) - if engine.first_game or engine.game != game or engine._opponent_changed(opponent): + if engine.first_game or engine.game != game or opponent_changed: engine.game = game - engine.play_opponent = opponent engine._ucinewgame() self.sent_isready = True engine._isready() From 28aa39a6b8fb64ce75e4024095995e754977b78b Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 00:09:31 -0700 Subject: [PATCH 038/250] Remove options handled by Opponent class --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 5fe95f960..80b757858 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2106,7 +2106,7 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponen # Set up starting position. root = board.root() - new_options = any(param in options for param in ("random", "computer", "name", "engine_rating", "opponent_rating")) + new_options = any(param in options for param in ("random", "computer")) new_game = self.first_game or self.game != game or new_options or opponent or root != self.board.root() self.game = game self.first_game = False From 191a1c1f8c1b41f20f35fb757148f7fafab00869 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 00:10:06 -0700 Subject: [PATCH 039/250] XBoard engines don't have to support name option --- chess/engine.py | 1 - 1 file changed, 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 80b757858..4b7b4b976 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1993,7 +1993,6 @@ def __init__(self) -> None: self.options = { "random": Option("random", "check", False, None, None, None), "computer": Option("computer", "check", False, None, None, None), - "name": Option("name", "string", "", None, None, None), "engine_rating": Option("engine_rating", "spin", 0, None, None, None), "opponent_rating": Option("opponent_rating", "spin", 0, None, None, None) } From 3685db1634d545b5198438192687ee0b3ecd8539 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 00:16:54 -0700 Subject: [PATCH 040/250] Protocol.target_config contains current opponent --- chess/engine.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 4b7b4b976..c99aa49a9 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2122,15 +2122,15 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponen if self.config.get("random"): self.send_line("random") - opponent_name = (opponent.name if opponent else None) or self.config.get("name") + opponent_name = (opponent.name if opponent else None) or self.target_config.get("name") if opponent_name and self.features.get("name", True): - self.send_line(f"name {self.config['name']}") + self.send_line(f"name {opponent_name}") - opponent_rating = (opponent.rating if opponent else None) or self.config.get("opponent_rating") or 0 - if self.config.get("engine_rating") or opponent_rating: - self.send_line(f"rating {self.config.get('engine_rating') or 0} {opponent_rating}") + opponent_rating = (opponent.rating if opponent else None) or self.target_config.get("opponent_rating") or 0 + if self.target_config.get("engine_rating") or opponent_rating: + self.send_line(f"rating {self.target_config.get('engine_rating') or 0} {opponent_rating}") - if (opponent and opponent.is_engine) or self.config.get("computer"): + if (opponent and opponent.is_engine) or (self.target_config.get("computer") if self.config.get("computer") is None else self.config.get("computer")): self.send_line("computer") self.send_line("force") From da4106369ccf13b9399e262d5757feb219041a47 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 00:50:56 -0700 Subject: [PATCH 041/250] Revert "XBoard engines don't have to support name option" This reverts commit 191a1c1f8c1b41f20f35fb757148f7fafab00869. The default is that XBoard engines accept the "name" feature. --- chess/engine.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chess/engine.py b/chess/engine.py index c99aa49a9..c3b863032 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1993,6 +1993,7 @@ def __init__(self) -> None: self.options = { "random": Option("random", "check", False, None, None, None), "computer": Option("computer", "check", False, None, None, None), + "name": Option("name", "string", "", None, None, None), "engine_rating": Option("engine_rating", "spin", 0, None, None, None), "opponent_rating": Option("opponent_rating", "spin", 0, None, None, None) } From 87ec56a9473a5074a89a592e0a2e68664795bdc6 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 00:52:29 -0700 Subject: [PATCH 042/250] Test sending opponent information to XBoard engine --- test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test.py b/test.py index a9dd5d89b..42f77ea68 100755 --- a/test.py +++ b/test.py @@ -3542,8 +3542,14 @@ async def main(): board.push_san("d4") board.push_san("Nf6") board.push_san("c4") + opponent = chess.engine.Opponent("Turk", None, 2100, True) + engine_rating = 3600 + await protocol.send_opponent_information(opponent=opponent, engine_rating=engine_rating) mock.expect("new") + mock.expect("name Turk") + mock.expect("rating 3600 2100") + mock.expect("computer") mock.expect("force") mock.expect("d2d4") mock.expect("g8f6") From a904617d389e0f179f24ab8e5b4b327d7bf15cdd Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 23:00:54 -0700 Subject: [PATCH 043/250] Complete opponent information --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 42f77ea68..f0ba7d9dc 100755 --- a/test.py +++ b/test.py @@ -3542,12 +3542,12 @@ async def main(): board.push_san("d4") board.push_san("Nf6") board.push_san("c4") - opponent = chess.engine.Opponent("Turk", None, 2100, True) + opponent = chess.engine.Opponent("Turk", "Mechanical", 2100, True) engine_rating = 3600 await protocol.send_opponent_information(opponent=opponent, engine_rating=engine_rating) mock.expect("new") - mock.expect("name Turk") + mock.expect("name Mechanical Turk") mock.expect("rating 3600 2100") mock.expect("computer") mock.expect("force") From 06e314531a6c653c537921faf70c2dce2813a57a Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 16 Mar 2023 23:16:31 -0700 Subject: [PATCH 044/250] Move XBoard opponent tests to own method --- test.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/test.py b/test.py index f0ba7d9dc..56843fde1 100755 --- a/test.py +++ b/test.py @@ -3542,14 +3542,8 @@ async def main(): board.push_san("d4") board.push_san("Nf6") board.push_san("c4") - opponent = chess.engine.Opponent("Turk", "Mechanical", 2100, True) - engine_rating = 3600 - await protocol.send_opponent_information(opponent=opponent, engine_rating=engine_rating) mock.expect("new") - mock.expect("name Mechanical Turk") - mock.expect("rating 3600 2100") - mock.expect("computer") mock.expect("force") mock.expect("d2d4") mock.expect("g8f6") @@ -3595,6 +3589,55 @@ async def main(): asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) + def test_xboard_opponent(self): + async def main(): + protocol = chess.engine.XBoardProtocol() + mock = chess.engine.MockTransport(protocol) + + mock.expect("xboard") + mock.expect("protover 2", ["feature ping=1 setboard=1 name=1 done=1"]) + await protocol.initialize() + mock.assert_done() + + limit = chess.engine.Limit(time=5) + board = chess.Board() + opponent = chess.engine.Opponent("Turk", "Mechanical", 2100, True) + await protocol.send_opponent_information(opponent=opponent, engine_rating=3600) + + mock.expect("new") + mock.expect("name Mechanical Turk") + mock.expect("rating 3600 2100") + mock.expect("computer") + mock.expect("force") + mock.expect("st 5") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move e2e4"]) + mock.expect_ping() + result = await protocol.play(board, limit, game="game") + self.assertEqual(result.move, board.parse_san("e4")) + mock.assert_done() + + new_opponent = chess.engine.Opponent("Turochamp", None, 800, True) + board.push(result.move) + mock.expect("new") + mock.expect("name Turochamp") + mock.expect("rating 3600 800") + mock.expect("computer") + mock.expect("force") + mock.expect("e2e4") + mock.expect("st 5") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move e7e5"]) + mock.expect_ping() + result = await protocol.play(board, limit, game="game", opponent=new_opponent) + self.assertEqual(result.move, board.parse_san("e5")) + mock.assert_done() + + asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) + asyncio.run(main()) + def test_xboard_analyse(self): async def main(): protocol = chess.engine.XBoardProtocol() From 7d670a489ae0da06f4a9275f82fcfbd42979bb6e Mon Sep 17 00:00:00 2001 From: snowdrop4 <82846066+snowdrop4@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:04:14 +0100 Subject: [PATCH 045/250] add BaseVisitor.begin_parse_san() method --- chess/pgn.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 8750443c5..553b6ece6 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1043,6 +1043,13 @@ def end_headers(self) -> Optional[SkipType]: """Called after visiting game headers.""" pass + def begin_parse_san(self, board: chess.Board, san: str) -> Optional[SkipType]: + """ + When the visitor is used by a parser, this is called at the start of + each standard algebraic notation detailing a move. + """ + pass + def parse_san(self, board: chess.Board, san: str) -> chess.Move: """ When the visitor is used by a parser, this is called to parse a move @@ -1682,14 +1689,15 @@ def read_game(handle: TextIO, *, Visitor: Any = GameBuilder) -> Any: visitor.visit_result(token) else: # Parse SAN tokens. - try: - move = visitor.parse_san(board_stack[-1], token) - except ValueError as error: - visitor.handle_error(error) - skip_variation_depth = 1 - else: - visitor.visit_move(board_stack[-1], move) - board_stack[-1].push(move) + if visitor.begin_parse_san(board_stack[-1], token) is not SKIP: + try: + move = visitor.parse_san(board_stack[-1], token) + except ValueError as error: + visitor.handle_error(error) + skip_variation_depth = 1 + else: + visitor.visit_move(board_stack[-1], move) + board_stack[-1].push(move) visitor.visit_board(board_stack[-1]) if fresh_line: From 039239718d4137c1b37cc212238303c27829c957 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 31 Mar 2023 18:20:19 +0200 Subject: [PATCH 046/250] Add another insufficient material test --- test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test.py b/test.py index 56843fde1..0ca635d43 100755 --- a/test.py +++ b/test.py @@ -579,6 +579,7 @@ def _check(board, white, black): _check(chess.variant.CrazyhouseBoard("8/8/8/8/3k4/3N~4/3K4/8 w - - 0 1"), False, False) _check(chess.variant.HordeBoard("8/5k2/8/8/8/4NN2/8/8 w - - 0 1"), True, False) + _check(chess.variant.HordeBoard("8/1b5r/1P6/1Pk3q1/1PP5/r1P5/P1P5/2P5 b - - 0 52"), False, False) def test_promotion_with_check(self): board = chess.Board("8/6P1/2p5/1Pqk4/6P1/2P1RKP1/4P1P1/8 w - - 0 1") From 12c6211360a36fce4cd1f324b76a2caa54a091e1 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 31 Mar 2023 18:42:59 +0200 Subject: [PATCH 047/250] Revert default Syzygy max_fds to 128 Python's mmap.mmap() actually (unnecessarily, with regard to our use case) duplicates the file descriptor and keeps a copy around for the lifetime of the memory map. --- chess/syzygy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 45eb963d0..2d835b200 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1483,7 +1483,7 @@ class Tablebase: """ Manages a collection of tablebase files for probing. """ - def __init__(self, *, max_fds: Optional[int] = None, VariantBoard: Type[chess.Board] = chess.Board) -> None: + def __init__(self, *, max_fds: Optional[int] = 128, VariantBoard: Type[chess.Board] = chess.Board) -> None: self.variant = VariantBoard self.max_fds = max_fds @@ -1963,7 +1963,7 @@ def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[ self.close() -def open_tablebase(directory: str, *, load_wdl: bool = True, load_dtz: bool = True, max_fds: Optional[int] = None, VariantBoard: Type[chess.Board] = chess.Board) -> Tablebase: +def open_tablebase(directory: str, *, load_wdl: bool = True, load_dtz: bool = True, max_fds: Optional[int] = 128, VariantBoard: Type[chess.Board] = chess.Board) -> Tablebase: """ Opens a collection of tables for probing. See :class:`~chess.syzygy.Tablebase`. From 363672783357ccfafb23a6917953ad4d61219047 Mon Sep 17 00:00:00 2001 From: Trevor Bayless Date: Fri, 31 Mar 2023 13:22:13 -0500 Subject: [PATCH 048/250] Add cli-chess --- README.rst | 5 +++++ docs/images/cli-chess.png | Bin 0 -> 3570 bytes 2 files changed, 5 insertions(+) create mode 100644 docs/images/cli-chess.png diff --git a/README.rst b/README.rst index aae81e788..cbacf299e 100644 --- a/README.rst +++ b/README.rst @@ -331,6 +331,11 @@ If you like, share interesting things you are using python-chess for, for exampl | :height: 64 | | | :target: https://pettingzoo.farama.org/environments/classic/chess/ | A multi-agent reinforcement learning environment | +------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+ +| .. image:: https://github.com/niklasf/python-chess/blob/master/docs/images/cli-chess.png?raw=true | `cli-chess `_ | +| :width: 64 | | +| :height: 64 | | +| :target: https://github.com/trevorbayless/cli-chess | A highly customizable way to play chess in your terminal | ++------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+ * extensions to build engines (search and evaluation) – https://github.com/Mk-Chan/python-chess-engine-extensions * a stand-alone chess computer based on DGT board – http://www.picochess.org/ diff --git a/docs/images/cli-chess.png b/docs/images/cli-chess.png new file mode 100644 index 0000000000000000000000000000000000000000..eaa7ff306749f925727ab7e958e4893309e2ca52 GIT binary patch literal 3570 zcmV%P)EX>4Tx04R}tkv&MmKpe$iKcpfR6+4IsW~fdUL`5963Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLx;QDiNQwVT3N2zhIPS;0dyl(!fWKa5su>&yRLwF{ ziMWu-t_q=71Tc&~^dcxRQ=b#XBs|C0J$!tC`-NgjguFvE0V2XsEe3JSuIyt^Pc>L;heUz%ypVWNMI355FtQD6(y8mAx5i4iis5M$36Umj$b5~Os*0b zITlcX3d!+<|H1EW&HUtqn-q=%9WS>1F#?2kfkw@?zmILZaRLOMfh(=$uhfB=Ptt2G zEqVm>Yy%h9Elu77E_Z-|CtWfmM+(sN=kvh(8GTb0=)VQJ*4*Bj`#607($rP*1~@nb zMhld^?(y!<_TK(I)9mjDBb9Q8=J;{+00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3ljhU3ljkVnw%H_000McNliru=K~)RBn=w!=-&VU02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{01L`VL_t(|+TELdR8(~u$3OSZ3o{HLGbkWQN(dBbxrAvi zZkX)0qQcr5C(TkZ;-u?tds+{@h;`OeC(S%`=#b%VZ6VmP&Yn88t9HUBC2DPuc+o78 z0^b^uh+$x0-hTTBF{=S9!^{Bf_nbLr?(g3F+~4!P&wbwR?;?cA1`tBb5JDUgKNC0{ z4$;xkF_KelLWpOC5J~{~N9B`&kAc~Y69^%&TCH?+bkN(|3xL&X#b`9LWy=;aGcz%n zOd}Dk0iFO}6+%c#Kmz^_7{*%Zo}M1+>gq6=OdL9N2(#G?z_xAM=gqF59SNeJ-`Fm0@qw^%F`6&3Np2OkW&KQ=a&)2B}lx-T*^lDxb;($dmUDwQL- zyjv1NI0402DBs@RPC-Ed_4V~W$w^B~vJU`gcu9uZ8jSP1qFQm`R9I- zmy(jgmMvQd2?_D)JbA24zpSjxZ^{E4J$jT~yLRF2{Tvel8X6iXEiLtnteBV>&;NJc zd54;sn(PS8tRk0TW-09tgI~0_Uo^|?v)jcIswOzAE&Oaj@xd# zjr;DqkFKsRpX60mR+5{W%ff{V0r={xuW-3s!#;n|*x_(EFq_Su49p+U>-886223Us zD_5>0DJhA~n>XXD4>p_4)YR0la^*_u>+9+2>Oz)f5CTW@w=jr!NuxnIdGg={9654? zmtJ~_=H_O<-uV|^cmadKfGo?*n>Ua3>(}G208~&=aM|{;W5<{|b0+rMFX-9+)WEx* zxts|bA0PM#96WfCjT<-mU3q}e&`?}17a18DY~Q}!uh#Wb?AWmbtJO;I;w7kld*ASU zfZ1&3*=L^(*rYl;J5eYUR8>`R;>3x7`kAJtCQ3?5a3c}A{*NdZF1s=TpMLr&4u>Nk z6VhljBqb$bu~;Z6DH#=K`|i8%vS-g8gj!A5pC3cL`uG2vfTKr`25d5m7A+z)G!&D` zo%GRx0ak^Y+ewjABJU|FRettehMMYeH{q;UiA~rUbuC6XV`Q#G{3JUo8>#u#1 z=WV`UQBi@@>HM+vF$@AEN#e85J|j6fnZm+CHf`EOczF1TCM!u26DLljwY8P3tSnS2 z71h<%J`u2K(H*Y3CKcA+iCeqW>dE<>Y$jQm+OESDn zfYfR=7K?>t%a&1IUhcC+O`JH9?c2ALot=$JrShcJnVFe9@x&8Mnlx#E#VD0Z+&0_r zGQobBOeRbw6HAvaB{w&hRjXDJ5fQ=j&p$ux$p!}pBg-;ZU3C?0ZEe)n*7~IU%{Sjn zM@I(<2??xUzn;~rS7WtW2?+^7r_%v2bLLF)^761)EC57BMfE+}wqaVprI_h-zQ!Leh<`V{KvL8s9W6%~a}tHpWd zG>)cI#Kgp~cJ12BI!Apuz8z`uR3xqT$`%k87stAF>qt#arMI`2_uhMt;^JbuySu%b zu+?g%si}$UuDfo?wwE`UGGz*Hz4aE^+1Y3>?FUK{%9yJ>n;97y+<4=S2qB1$js`$G ze*xOGJFol*xZQ4wii*(bbW~SYQ(Rn3Q&ZE3Cp~%cWLjHW{gPszK7E?3tSqXks#vgK z0d8w2uJbKF@nJHm*lEPY#r0W=y%*=VClL;N-+pZ{$|-UG+XBv>Jxh6cIUj%gu}>2Y z4-aR;gb954<(HnZ>C>mv*w{ECc?S+0VCT-AJoeaQq^714rVGaYuh(&(GXBK%hag2= zha^e3%_qQa@$6E}`W?!g{Gok-EX(BO<@u~Uz_e-8kY(AEXzBHO?!5EP5z9Mw?i?*G zEv#9yhO)9UP$ zB_Jp$$kSv|tJS2Wq_AVh4xb1(bm$PZwY98SvxfZqe6G3X8X{)jfvYYHSN*$zCE()4 zi#++{lLN-joH@f#-KG9SWyz8y^!E1tn3np6!oos|i;G#eZXG2hCFJMlqxs!Kbe%W| zj?Tal;B-2vtgIaN@$K#H9?O|KckX~!Un50xb2D$g`6g@EuBE!VnyRWQZomC@)Jy(^ z{U3iBKTXk=mKKB%==FNy_k0x0aECc@k79O z-+hP8W+Nsh27|$HS=kK`5fR~&{B7H|A%tMXiWPkL;fF{XEvjGTj2{Ao5S%}Mp2)~Z zBuVl_1At}Amia9I%$YOn*|Uc^bLOyr|9)&X8>*Q%4_f+;2?714+Sb+vfZcBQlh(x}6&iEnVqmMq~@ZrOrBnx2m>eWL=j*(c|?%lh& z;f5PLg_2^{e59C^!GB?fkw<}%qNk_FQ=3bY#I3j9$}`VA<2U(6qmk_FY`*y73m$mj z0W|4LA$_U;!{A8KUz_XodQwwU(d+eoZ;#j3*3#3{gWK&!vUlRP3~phPDi~QGH@XCz zJ$u&E&6zuQE_S=!V-@~FMMVW#t+wxtQ+FG#ZwAi_rLct2C!nUL2A9i4OiT=6VPOPf zT}ESLBhk^($g+%ZJI9X`>@SAe+uJ?)Ku}N+*Is+A->;LHn201v2z%%FBA`Eg4G#|| zGBOgCN=0E|AxoAl@tgel^XGH_{rC4phVBdFkAVJ$XjoVn7K;V7TFt``KTK?Ftk1G@ za&jmrC?GL05n*e`-F|HR5l~iEhS6x`#EBC;_uO;5|Ni^vbUIe7SmAS@@ZNjxMS%Z$*}uRnS6B#Rd>CO$siC%G9J83Y9d;cTwNec|6;ojYc$ z#HLQ2N>Nb}3WWmgC2i`FpnrX!BIYKfkZC^;0yb>eKy-98Cr_UAs=qK8OePaGH8luD z5X!jU1hymOFC-)+(AL(*Lk~TK+wJx_4K^B$y!hga%$hX|RAJz-jBf&5E*C153cX(M zmx@r5B+sKHhg^+t+J-(>8#(p_w6(R7n3%}RFTc$4<;%TV+BQ^UBq=GWPpQPr@%;!S zCnpmhAJ6&o=h?7fgU`wXJpTCOY~8w*)YMeIx?tnm_MyXIgjPZ7)gfa?z|y5lQ79A~ zIBglT*wLoJ zMy2Y!UauY&0dBw(Lj#Ha^}&HAJ2*HP0Eb%)ivTmgoH=s>PC#R0BOM(bBqt|x(@i%8 z?QQUFI9SESR^@FEI_K&e!sR;%gl?e%)C(Qsk6+v)D^Mgk0~ zE4sLoGO!OgrBEn%I~3On|-*C;tlc se`^*3{1*5H5XAo<%)oxY^TFbO06cqLazxc|uK)l507*qoM6N<$f Date: Fri, 7 Apr 2023 19:46:12 -0400 Subject: [PATCH 049/250] Add square_manhattan_distance and square_knight_distance --- chess/__init__.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/chess/__init__.py b/chess/__init__.py index e205bba8e..d6ef1d153 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -218,10 +218,41 @@ def square_rank(square: Square) -> int: def square_distance(a: Square, b: Square) -> int: """ - Gets the distance (i.e., the number of king steps) from square *a* to *b*. + Gets the Chebyshev distance (i.e., the number of king steps) from square *a* to *b*. """ + if a == b: + return 0; return max(abs(square_file(a) - square_file(b)), abs(square_rank(a) - square_rank(b))) +def square_manhattan_distance(a: Square, b: Square) -> int: + """ + Gets the Manhattan/Taxicab distance (i.e., the number of orthogonal king steps) from square *a* to *b*. + """ + if a == b: + return 0; + return abs(square_file(a) - square_file(b)) + abs(square_rank(a) - square_rank(b)) + +def square_knight_distance(a: Square, b: Square) -> int: + """ + Gets the Knight distance (i.e., the number of knight moves) from square *a* to *b*. + """ + if a == b: + return 0; + + dx = abs(square_file(a) - square_file(b)) + dy = abs(square_rank(a) - square_rank(b)) + + if dx + dy == 1: + return 3 + elif dx == dy == 2: + return 4 + elif dx == dy == 1: + if 1 << a & BB_CORNERS or 1 << b & BB_CORNERS: # Special case only for corner squares + return 4 + + m = math.ceil(max(dx / 2, dy / 2, (dx + dy) / 3)) + return m + ((m + dx + dy) % 2) + def square_mirror(square: Square) -> Square: """Mirrors the square vertically.""" return square ^ 0x38 From 9cc4372dce66eb4757eb3ae9adc676e3965a152e Mon Sep 17 00:00:00 2001 From: AInnuganti <130129680+AInnuganti@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:42:34 -0400 Subject: [PATCH 050/250] Made requested changes --- chess/__init__.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index d6ef1d153..980dc34b4 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -220,25 +220,18 @@ def square_distance(a: Square, b: Square) -> int: """ Gets the Chebyshev distance (i.e., the number of king steps) from square *a* to *b*. """ - if a == b: - return 0; return max(abs(square_file(a) - square_file(b)), abs(square_rank(a) - square_rank(b))) def square_manhattan_distance(a: Square, b: Square) -> int: """ Gets the Manhattan/Taxicab distance (i.e., the number of orthogonal king steps) from square *a* to *b*. """ - if a == b: - return 0; return abs(square_file(a) - square_file(b)) + abs(square_rank(a) - square_rank(b)) def square_knight_distance(a: Square, b: Square) -> int: """ Gets the Knight distance (i.e., the number of knight moves) from square *a* to *b*. """ - if a == b: - return 0; - dx = abs(square_file(a) - square_file(b)) dy = abs(square_rank(a) - square_rank(b)) @@ -247,7 +240,7 @@ def square_knight_distance(a: Square, b: Square) -> int: elif dx == dy == 2: return 4 elif dx == dy == 1: - if 1 << a & BB_CORNERS or 1 << b & BB_CORNERS: # Special case only for corner squares + if BB_SQUARES[a] & BB_CORNERS or BB_SQUARES[b] & BB_CORNERS: # Special case only for corner squares return 4 m = math.ceil(max(dx / 2, dy / 2, (dx + dy) / 3)) From a2f1588e20123f946b1eaf98492b35e87739e26d Mon Sep 17 00:00:00 2001 From: AInnuganti <130129680+AInnuganti@users.noreply.github.com> Date: Sat, 15 Apr 2023 23:32:50 -0400 Subject: [PATCH 051/250] Add tests for new distance functions --- test.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test.py b/test.py index 0ca635d43..17dec2916 100755 --- a/test.py +++ b/test.py @@ -93,6 +93,31 @@ def test_parse_square(self): with self.assertRaises(ValueError): self.assertEqual(chess.parse_square("a0")) + def test_square_distance(self): + self.assertEqual(chess.square_distance(chess.A1, chess.A1), 0) + self.assertEqual(chess.square_distance(chess.A1, chess.H8), 7) + self.assertEqual(chess.square_distance(chess.E1, chess.E8), 7) + self.assertEqual(chess.square_distance(chess.A4, chess.H4), 7) + self.assertEqual(chess.square_distance(chess.D4, chess.E5), 1) + + def test_square_manhattan_distance(self): + self.assertEqual(chess.square_manhattan_distance(chess.A1, chess.A1), 0) + self.assertEqual(chess.square_manhattan_distance(chess.A1, chess.H8), 14) + self.assertEqual(chess.square_manhattan_distance(chess.E1, chess.E8), 7) + self.assertEqual(chess.square_manhattan_distance(chess.A4, chess.H4), 7) + self.assertEqual(chess.square_manhattan_distance(chess.D4, chess.E5), 2) + + def test_square_knight_distance(self): + self.assertEqual(chess.square_knight_distance(chess.A1, chess.A1), 0) + self.assertEqual(chess.square_knight_distance(chess.A1, chess.H8), 6) + self.assertEqual(chess.square_knight_distance(chess.G1, chess.F3), 1) + self.assertEqual(chess.square_knight_distance(chess.E1, chess.E8), 5) + self.assertEqual(chess.square_knight_distance(chess.A4, chess.H4), 5) + self.assertEqual(chess.square_knight_distance(chess.A1, chess.B1), 3) + self.assertEqual(chess.square_knight_distance(chess.A1, chess.C3), 4) + self.assertEqual(chess.square_knight_distance(chess.A1, chess.B2), 4) + self.assertEqual(chess.square_knight_distance(chess.C1, chess.B2), 2) + class MoveTestCase(unittest.TestCase): From d5da1d5849fdd85f7fc19d49d57cc38729906e6a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 16 Apr 2023 09:42:15 +0200 Subject: [PATCH 052/250] Add new distance functions to docs (#986) --- docs/core.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/core.rst b/docs/core.rst index d5790820a..8bb045bbb 100644 --- a/docs/core.rst +++ b/docs/core.rst @@ -85,6 +85,10 @@ and so on to .. autofunction:: chess.square_distance +.. autofunction:: chess.square_manhattan_distance + +.. autofunction:: chess.square_knight_distance + .. autofunction:: chess.square_mirror Pieces From bd371f68b631499d9107c20f1f785b111c547f62 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 22 Apr 2023 20:43:01 +0200 Subject: [PATCH 053/250] Remove SVG version and baseProfile https://github.com/niklasf/python-chess/discussions/992 --- chess/svg.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index 008b0c87c..94ae21569 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -169,8 +169,6 @@ def _svg(viewbox: int, size: Optional[int]) -> ET.Element: svg = ET.Element("svg", { "xmlns": "http://www.w3.org/2000/svg", "xmlns:xlink": "http://www.w3.org/1999/xlink", - "version": "1.2", - "baseProfile": "tiny", "viewBox": f"0 0 {viewbox:d} {viewbox:d}", }) From dc2e284e9ddf909720a2bbe32e994269d4168244 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 24 Apr 2023 20:58:29 -0700 Subject: [PATCH 054/250] Send the final result of a game to engines UCI engines receive the final board position. Xboard engines receive the final move of the game and a message describing the winner and reason for the game ending. --- chess/engine.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/chess/engine.py b/chess/engine.py index c3b863032..afb4c9d8a 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1246,6 +1246,27 @@ async def analysis(self, board: chess.Board, limit: Optional[Limit] = None, *, m and stopping the analysis at any time. """ + @abc.abstractmethod + async def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: + """ + Sends the engine the result of the game. + + UCI engines only recieve the final position of the board. XBoard engines + receive the final moves and a line of the form "result {}", + where is one of "1-0", "0-1", "1/2-1/2", or "*" to indicate white + won, black won, draw, or adjournment, respectively. + + :param board: The final state of the board. + :param winner: Optional. Specify the winner of the game. This is useful + if the result of the game is not evident from the board--e.g., time + forfeiture or draw by agreement. + :param game_ending: Optional. Text describing the reason for the game + ending. Similarly to the winner paramter, this overrides any game + result derivable from the board. + :param game_complete: Optional. Whether the game is complete or may resume + at a later time. + """ + @abc.abstractmethod async def quit(self) -> None: """Asks the engine to shut down.""" @@ -1797,6 +1818,15 @@ def engine_terminated(self, engine: UciProtocol, exc: Exception) -> None: return await self.communicate(UciAnalysisCommand) + async def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: + class UciGameResultCommand(BaseCommand[UciProtocol, None]): + def start(self, engine: UciProtocol) -> None: + engine._position(board) # Send final board position + self.result.set_result(None) + self.set_finished() + + return await self.communicate(UciGameResultCommand) + async def quit(self) -> None: self.send_line("quit") await asyncio.shield(self.returncode) @@ -2477,6 +2507,38 @@ def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) + async def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: + class XBoardGameResultCommand(BaseCommand[XBoardProtocol, None]): + def start(self, engine: XBoardProtocol) -> None: + engine._new(board, engine.game, {}) # Send final moves to engine. + + outcome = board.outcome(claim_draw=True) + + if not game_complete: + result = "*" + ending = game_ending or "Game adjourned" + elif winner is not None or game_ending: + result = "1-0" if winner == chess.WHITE else ("0-1" if winner == chess.BLACK else "1/2-1/2") + ending = game_ending or "" + elif outcome is not None and outcome.winner is not None: + result = outcome.result() + winning_color = "White" if outcome.winner == chess.WHITE else "Black" + is_checkmate = outcome.termination == chess.Termination.CHECKMATE + ending = f"{winning_color} {'mates' if is_checkmate else 'variant win'}" + elif outcome is not None: + result = outcome.result() + ending = outcome.termination.name.capitalize().replace("_", " ") + else: + result = "*" + ending = "" + + ending_text = f"{{{ending}}}" if ending else "" + engine.send_line(f"result {result} {ending_text}".strip()) + self.result.set_result(None) + self.set_finished() + + return await self.communicate(XBoardGameResultCommand) + async def quit(self) -> None: self.send_line("quit") await asyncio.shield(self.returncode) @@ -2904,6 +2966,12 @@ def analysis(self, board: chess.Board, limit: Optional[Limit] = None, *, multipv future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return SimpleAnalysisResult(self, future.result()) + def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: + with self._not_shut_down(): + coro = asyncio.wait_for(self.protocol.send_game_result(board, winner, game_ending, game_complete), self.timeout) + future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) + return future.result() + def quit(self) -> None: with self._not_shut_down(): coro = asyncio.wait_for(self.protocol.quit(), self.timeout) From 91996e2d9043a8eab3885e1fa30cd93ec5da80b2 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 25 Apr 2023 21:14:26 -0700 Subject: [PATCH 055/250] Do nothing for UCI engines UCI engines do not expect to get a message once a game ends. --- chess/engine.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index afb4c9d8a..75dd3633b 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1819,13 +1819,7 @@ def engine_terminated(self, engine: UciProtocol, exc: Exception) -> None: return await self.communicate(UciAnalysisCommand) async def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: - class UciGameResultCommand(BaseCommand[UciProtocol, None]): - def start(self, engine: UciProtocol) -> None: - engine._position(board) # Send final board position - self.result.set_result(None) - self.set_finished() - - return await self.communicate(UciGameResultCommand) + pass async def quit(self) -> None: self.send_line("quit") From ee210f4a9fbc9286863b3f495259708b95bd7846 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 25 Apr 2023 21:15:00 -0700 Subject: [PATCH 056/250] Make default message for incomplete game blank --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 75dd3633b..314dfc753 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2510,7 +2510,7 @@ def start(self, engine: XBoardProtocol) -> None: if not game_complete: result = "*" - ending = game_ending or "Game adjourned" + ending = game_ending or "" elif winner is not None or game_ending: result = "1-0" if winner == chess.WHITE else ("0-1" if winner == chess.BLACK else "1/2-1/2") ending = game_ending or "" From f4d73525c97d4a4aa604481b4e8a37b55fb2caf8 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 25 Apr 2023 21:45:48 -0700 Subject: [PATCH 057/250] Tests for sending game result --- test.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/test.py b/test.py index 17dec2916..b52f38590 100755 --- a/test.py +++ b/test.py @@ -3664,6 +3664,80 @@ async def main(): asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) + def test_xboard_result(self): + async def main(): + protocol = chess.engine.XBoardProtocol() + mock = chess.engine.MockTransport(protocol) + + mock.expect("xboard") + mock.expect("protover 2", ["feature ping=1 setboard=1 done=1"]) + await protocol.initialize() + mock.assert_done() + + limit = chess.engine.Limit(time=5) + checkmate_board = chess.Board("k7/7R/6R1/8/8/8/8/K7 w - - 0 1") + + mock.expect("new") + mock.expect("force") + mock.expect("setboard k7/7R/6R1/8/8/8/8/K7 w - - 0 1") + mock.expect("st 5") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move g6g8"]) + mock.expect_ping() + mock.expect("force") + mock.expect("result 1-0 {White mates}") + result = await protocol.play(checkmate_board, limit, game="checkmate") + self.assertEqual(result.move, checkmate_board.parse_uci("g6g8")) + checkmate_board.push(result.move) + self.assertTrue(checkmate_board.is_checkmate()) + await protocol.send_game_result(checkmate_board) + mock.assert_done() + + unfinished_board = chess.Board() + mock.expect("new") + mock.expect("force") + mock.expect("st 5") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move e2e4"]) + mock.expect_ping() + mock.expect("force") + mock.expect("result *") + result = await protocol.play(unfinished_board, limit, game="unfinished") + self.assertEqual(result.move, unfinished_board.parse_uci("e2e4")) + unfinished_board.push(result.move) + await protocol.send_game_result(unfinished_board, game_complete=False) + mock.assert_done() + + timeout_board = chess.Board() + mock.expect("new") + mock.expect("force") + mock.expect("st 5") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move e2e4"]) + mock.expect_ping() + mock.expect("force") + mock.expect("result 0-1 {Time forfeiture}") + result = await protocol.play(timeout_board, limit, game="timeout") + self.assertEqual(result.move, timeout_board.parse_uci("e2e4")) + timeout_board.push(result.move) + await protocol.send_game_result(timeout_board, chess.BLACK, "Time forfeiture") + mock.assert_done() + + material_board = chess.Board("k7/8/8/8/8/8/8/K7 b - - 0 1") + self.assertTrue(material_board.is_insufficient_material()) + mock.expect("new") + mock.expect("force") + mock.expect("setboard k7/8/8/8/8/8/8/K7 b - - 0 1") + mock.expect("result 1/2-1/2 {Insufficient material}") + await protocol.send_game_result(material_board) + mock.assert_done() + + asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) + asyncio.run(main()) + def test_xboard_analyse(self): async def main(): protocol = chess.engine.XBoardProtocol() From e5d8c6d9232037e616ee8a540ea73b3247560049 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 25 Apr 2023 21:48:34 -0700 Subject: [PATCH 058/250] Edit parameter comment --- chess/engine.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 314dfc753..0f91bca3f 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1263,8 +1263,7 @@ async def send_game_result(self, board: chess.Board, winner: Optional[Color] = N :param game_ending: Optional. Text describing the reason for the game ending. Similarly to the winner paramter, this overrides any game result derivable from the board. - :param game_complete: Optional. Whether the game is complete or may resume - at a later time. + :param game_complete: Optional. Whether the game reached completion. """ @abc.abstractmethod From 0512fe01c32cef2bdcbb46d9afe15ecae98eadd4 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 25 Apr 2023 22:42:56 -0700 Subject: [PATCH 059/250] Add test for do-nothing UCI send_game_result() --- test.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test.py b/test.py index b52f38590..fd3b93ed8 100755 --- a/test.py +++ b/test.py @@ -3465,6 +3465,32 @@ def test_uci_info(self): info = chess.engine._parse_uci_info("depth 1 seldepth 2 time 16 nodes 1 score cp 72 wdl 249 747 4 hashfull 0 nps 400 tbhits 0 multipv 1", board) self.assertEqual(info["wdl"], (249, 747, 4)) + def test_uci_result(self): + async def main(): + protocol = chess.engine.UciProtocol() + mock = chess.engine.MockTransport(protocol) + + mock.expect("uci", ["uciok"]) + await protocol.initialize() + mock.assert_done() + + limit = chess.engine.Limit(time=5) + checkmate_board = chess.Board("k7/7R/6R1/8/8/8/8/K7 w - - 0 1") + + mock.expect("ucinewgame") + mock.expect("isready", ["readyok"]) + mock.expect("position fen k7/7R/6R1/8/8/8/8/K7 w - - 0 1") + mock.expect("go movetime 5000", ["bestmove g6g8"]) + result = await protocol.play(checkmate_board, limit, game="checkmate") + self.assertEqual(result.move, checkmate_board.parse_uci("g6g8")) + checkmate_board.push(result.move) + self.assertTrue(checkmate_board.is_checkmate()) + await protocol.send_game_result(checkmate_board) + mock.assert_done() + + asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) + asyncio.run(main()) + def test_hiarcs_bestmove(self): async def main(): protocol = chess.engine.UciProtocol() From 885d59f708423fd3a1f18ae1fb9a35532dc51293 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 25 Apr 2023 22:48:10 -0700 Subject: [PATCH 060/250] Delete unneeded parentheses --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 0f91bca3f..ae33db688 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2511,7 +2511,7 @@ def start(self, engine: XBoardProtocol) -> None: result = "*" ending = game_ending or "" elif winner is not None or game_ending: - result = "1-0" if winner == chess.WHITE else ("0-1" if winner == chess.BLACK else "1/2-1/2") + result = "1-0" if winner == chess.WHITE else "0-1" if winner == chess.BLACK else "1/2-1/2" ending = game_ending or "" elif outcome is not None and outcome.winner is not None: result = outcome.result() From 622f3a0b8cbf7098082dca20f86d98a2a5e5f171 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 29 Apr 2023 23:42:00 +0200 Subject: [PATCH 061/250] Add perft with impossible castling rights --- examples/perft/tricky.perft | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/perft/tricky.perft b/examples/perft/tricky.perft index b3cca9fd2..6a572a330 100644 --- a/examples/perft/tricky.perft +++ b/examples/perft/tricky.perft @@ -129,3 +129,15 @@ epd rnbqk1nr/bb3p1p/1q2r3/2pPp3/3P4/7P/1PP1NpPP/R1BQKBNR w KQkq c6 perft 1 2 perft 2 92 perft 3 2528 + +# +# Impossible castling rights +# + +id asymmetrical-and-king-on-h +epd r2r3k/p7/3p4/8/8/P6P/8/R3K2R b KQq - +perft 1 14 +perft 2 206 +perft 3 3672 +perft 4 64639 +perft 5 1320962 From 4889834dc0f1a2eb7f56440c87d4d1490c5f3f4b Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 29 Apr 2023 21:47:08 -0700 Subject: [PATCH 062/250] Add optional identifier to Limit instances This new field in the Limit class is used to signal when the time control for a game has changed. XBoard engines expect to receive a `level` or `st` command to indicate the time control at the start of the game, and then only `time` and `otim` commands before each subsequent move to update the engine's internal clocks. The `level` and `st` commands should only be resent when the time control changes--like in FIDE tournament time controls. During a single time control, the same `clock_id` should be used for every Limit instance. This field has a similar function to the `game` parameter of the `play()` method. --- chess/engine.py | 25 +++++++++++++++++++------ test.py | 21 +++++++++++++++++++-- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c3b863032..722d2be36 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -332,6 +332,14 @@ class Limit: *white_clock* and *black_clock* are, then it is sudden death. """ + clock_id: object = None + """ + An identifier to use with XBoard engines to signal that the time + control has changed. When this field changes, Xboard engines are + send level or st commands as appropriate. Otherwise, only time + and otim commands are sent to update the engine's clock. + """ + def __repr__(self) -> str: # Like default __repr__, but without None values. return "{}({})".format( @@ -2001,6 +2009,7 @@ def __init__(self) -> None: self.target_config: Dict[str, ConfigValue] = {} self.board = chess.Board() self.game: object = None + self.clock_id: object = None self.first_game = True async def initialize(self) -> None: @@ -2202,10 +2211,9 @@ def start(self, engine: XBoardProtocol) -> None: # Limit or time control. clock = limit.white_clock if board.turn else limit.black_clock increment = limit.white_inc if board.turn else limit.black_inc - if limit.remaining_moves or clock is not None or increment is not None: - base_mins, base_secs = divmod(int(clock or 0), 60) - engine.send_line(f"level {limit.remaining_moves or 0} {base_mins}:{base_secs:02d} {increment or 0}") - + if limit.clock_id is None or limit.clock_id != engine.clock_id: + self._send_time_control(engine, clock, increment) + engine.clock_id = limit.clock_id if limit.nodes is not None: if limit.time is not None or limit.white_clock is not None or limit.black_clock is not None or increment is not None: raise EngineError("xboard does not support mixing node limits with time limits") @@ -2217,8 +2225,6 @@ def start(self, engine: XBoardProtocol) -> None: engine.send_line("nps 1") engine.send_line(f"st {max(1, int(limit.nodes))}") - if limit.time is not None: - engine.send_line(f"st {max(0.01, limit.time)}") if limit.depth is not None: engine.send_line(f"sd {max(1, int(limit.depth))}") if limit.white_clock is not None: @@ -2270,6 +2276,13 @@ def line_received(self, engine: XBoardProtocol, line: str) -> None: else: LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + def _send_time_control(self, engine: XBoardProtocol, clock: Optional[float], increment: Optional[float]) -> None: + if limit.remaining_moves or clock is not None or increment is not None: + base_mins, base_secs = divmod(int(clock or 0), 60) + engine.send_line(f"level {limit.remaining_moves or 0} {base_mins}:{base_secs:02d} {increment or 0}") + if limit.time is not None: + engine.send_line(f"st {max(0.01, limit.time)}") + def _post(self, engine: XBoardProtocol, line: str) -> None: if not self.result.done(): self.play_result.info = _parse_xboard_post(line, engine.board, info) diff --git a/test.py b/test.py index 17dec2916..d6d0b3926 100755 --- a/test.py +++ b/test.py @@ -3713,7 +3713,9 @@ async def main(): mock.assert_done() limit = chess.engine.Limit(black_clock=65, white_clock=100, - black_inc=4, white_inc=8) + black_inc=4, white_inc=8, + clock_id="xboard level") + board = chess.Board() mock.expect("new") mock.expect("force") mock.expect("level 0 1:40 8") @@ -3723,10 +3725,25 @@ async def main(): mock.expect("easy") mock.expect("go", ["move e2e4"]) mock.expect_ping() - result = await protocol.play(chess.Board(), limit) + result = await protocol.play(board, limit) self.assertEqual(result.move, chess.Move.from_uci("e2e4")) mock.assert_done() + board.push(result.move) + board.push_uci("e7e5") + + mock.expect("force") + mock.expect("e7e5") + mock.expect("time 10000") + mock.expect("otim 6500") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move d2d4"]) + mock.expect_ping() + result = await protocol.play(board, limit) + self.assertEqual(result.move, chess.Move.from_uci("d2d4")) + mock.assert_done() + asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) From 13ef9447ae2a6063b06200965f923fc34a872ba5 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 30 Apr 2023 11:59:51 +0200 Subject: [PATCH 063/250] Try Sphinx 7.0.0 --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 8f65fe1fd..526215aee 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -Sphinx==6.1.2 +Sphinx==7.0.0 From e73121a0caea542bc493ad72b59d7fbc17e02633 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 30 Apr 2023 13:37:13 +0200 Subject: [PATCH 064/250] Revert "Try Sphinx 7.0.0" This reverts commit 13ef9447ae2a6063b06200965f923fc34a872ba5. --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 526215aee..8f65fe1fd 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -Sphinx==7.0.0 +Sphinx==6.1.2 From 29bf03e1b030f761589ace9fe75da5152853f6c4 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 May 2023 13:09:36 +0200 Subject: [PATCH 065/250] Add perft with pinned ep capturer and impossible check --- examples/perft/tricky.perft | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/perft/tricky.perft b/examples/perft/tricky.perft index 6a572a330..2510a9aea 100644 --- a/examples/perft/tricky.perft +++ b/examples/perft/tricky.perft @@ -124,6 +124,12 @@ perft 1 6 perft 2 121 perft 3 711 +id align-ep-pinned +epd 1b1k4/8/8/1rPpK3/8/8/8/8 w - d6 +perft 1 5 +perft 2 100 +perft 3 555 + id ep-unrelated-check epd rnbqk1nr/bb3p1p/1q2r3/2pPp3/3P4/7P/1PP1NpPP/R1BQKBNR w KQkq c6 perft 1 2 From 736478a1c7cd798cd7a603b92a5ac7dff692349b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 2 May 2023 20:58:22 +0200 Subject: [PATCH 066/250] Work around jQuery removed from Sphinx (fixes #1006) --- docs/conf.py | 7 ++++++- docs/requirements.txt | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index bde54010b..ede90b63b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,12 @@ } # Autodoc. -extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.intersphinx"] +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.intersphinx", + "sphinxcontrib.jquery" +] autodoc_member_order = "bysource" intersphinx_mapping = { "python": ("https://docs.python.org/3", None), diff --git a/docs/requirements.txt b/docs/requirements.txt index 8f65fe1fd..d99b8c473 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,2 @@ Sphinx==6.1.2 +sphinxcontrib-jquery==4.1 From 40e633bab5145945536c45fd178e8dd9a265ae1f Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 3 May 2023 03:04:37 -0700 Subject: [PATCH 067/250] Correct grammar --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 722d2be36..5b921de70 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -336,7 +336,7 @@ class Limit: """ An identifier to use with XBoard engines to signal that the time control has changed. When this field changes, Xboard engines are - send level or st commands as appropriate. Otherwise, only time + sent level or st commands as appropriate. Otherwise, only time and otim commands are sent to update the engine's clock. """ From c3bc113bcc765dd51f998dc2be83b32c1345091f Mon Sep 17 00:00:00 2001 From: johndoknjas Date: Sun, 4 Jun 2023 18:39:59 -0700 Subject: [PATCH 068/250] Small cleanups. --- chess/engine.py | 8 ++++---- chess/pgn.py | 5 +---- chess/polyglot.py | 5 +---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c3b863032..65fc8f6c2 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1532,7 +1532,7 @@ def start(self, engine: UciProtocol) -> None: return await self.communicate(UciConfigureCommand) - def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> ConfigMapping: + def _opponent_configuration(self, *, opponent: Optional[Opponent] = None) -> ConfigMapping: if opponent and opponent.name and "UCI_Opponent" in self.options: rating = opponent.rating or "none" title = opponent.title or "none" @@ -1542,7 +1542,7 @@ def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine return {} async def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engine_rating: Optional[int] = None) -> None: - return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) + return await self.configure(self._opponent_configuration(opponent=opponent)) def _position(self, board: chess.Board) -> None: # Select UCI_Variant and UCI_Chess960. @@ -1932,7 +1932,7 @@ def _chain_config(a: ConfigMapping, b: ConfigMapping) -> Iterator[Tuple[str, Con class UciOptionMap(MutableMapping[str, T]): """Dictionary with case-insensitive keys.""" - def __init__(self, data: Optional[Union[Iterable[Tuple[str, T]]]] = None, **kwargs: T) -> None: + def __init__(self, data: Optional[Iterable[Tuple[str, T]]] = None, **kwargs: T) -> None: self._store: Dict[str, Tuple[str, T]] = {} if data is None: data = {} @@ -1948,7 +1948,7 @@ def __delitem__(self, key: str) -> None: del self._store[key.lower()] def __iter__(self) -> Iterator[str]: - return (casedkey for casedkey, mappedvalue in self._store.values()) + return (casedkey for casedkey, _ in self._store.values()) def __len__(self) -> int: return len(self._store) diff --git a/chess/pgn.py b/chess/pgn.py index 553b6ece6..1f99f6506 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -942,10 +942,7 @@ def __setitem__(self, key: str, value: str) -> None: self._others[key] = value def __getitem__(self, key: str) -> str: - if key in TAG_ROSTER: - return self._tag_roster[key] - else: - return self._others[key] + return self._tag_roster[key] if key in TAG_ROSTER else self._others[key] def __delitem__(self, key: str) -> None: if key in TAG_ROSTER: diff --git a/chess/polyglot.py b/chess/polyglot.py index c56c5ecfb..39270c129 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -391,11 +391,8 @@ def __getitem__(self, index: int) -> Entry: return Entry(key, raw_move, weight, learn, move) def __iter__(self) -> Iterator[Entry]: - i = 0 - size = len(self) - while i < size: + for i in range(len(self)): yield self[i] - i += 1 def bisect_key_left(self, key: int) -> int: lo = 0 From 67aa18e3bb78d245d6762e514c0037f519c7a30f Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 7 Jul 2023 22:49:38 +0200 Subject: [PATCH 069/250] Fix typo in docs: INFO_BASE -> INFO_BASIC --- chess/engine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c3b863032..22de2b440 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1155,7 +1155,7 @@ async def play(self, board: chess.Board, limit: Limit, *, game: object = None, i Will automatically inform the engine if the object is not equal to the previous game (e.g., ``ucinewgame``, ``new``). :param info: Selects which additional information to retrieve from the - engine. ``INFO_NONE``, ``INFO_BASE`` (basic information that is + engine. ``INFO_NONE``, ``INFO_BASIC`` (basic information that is trivial to obtain), ``INFO_SCORE``, ``INFO_PV``, ``INFO_REFUTATION``, ``INFO_CURRLINE``, ``INFO_ALL`` or any bitwise combination. Some overhead is associated with parsing @@ -1197,7 +1197,7 @@ async def analyse(self, board: chess.Board, limit: Limit, *, multipv: Optional[i Will automatically inform the engine if the object is not equal to the previous game (e.g., ``ucinewgame``, ``new``). :param info: Selects which information to retrieve from the - engine. ``INFO_NONE``, ``INFO_BASE`` (basic information that is + engine. ``INFO_NONE``, ``INFO_BASIC`` (basic information that is trivial to obtain), ``INFO_SCORE``, ``INFO_PV``, ``INFO_REFUTATION``, ``INFO_CURRLINE``, ``INFO_ALL`` or any bitwise combination. Some overhead is associated with parsing @@ -1230,7 +1230,7 @@ async def analysis(self, board: chess.Board, limit: Optional[Limit] = None, *, m Will automatically inform the engine if the object is not equal to the previous game (e.g., ``ucinewgame``, ``new``). :param info: Selects which information to retrieve from the - engine. ``INFO_NONE``, ``INFO_BASE`` (basic information that is + engine. ``INFO_NONE``, ``INFO_BASIC`` (basic information that is trivial to obtain), ``INFO_SCORE``, ``INFO_PV``, ``INFO_REFUTATION``, ``INFO_CURRLINE``, ``INFO_ALL`` or any bitwise combination. Some overhead is associated with parsing From c4611185b060635bf6b4aef30f7daf75e9737b22 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 8 Jul 2023 17:26:00 +0200 Subject: [PATCH 070/250] Add sf16 WDL model --- chess/engine.py | 18 +++++++++++++++--- test.py | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 22de2b440..55c5bc9b0 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -44,7 +44,7 @@ try: from typing import Literal - _WdlModel = Literal["sf", "sf15.1", "sf15", "sf14", "sf12", "lichess"] + _WdlModel = Literal["sf", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] except ImportError: # Before Python 3.8. _WdlModel = str # type: ignore @@ -637,11 +637,20 @@ def __ge__(self, other: object) -> bool: else: return NotImplemented +def _sf16_wins(cp: int, *, ply: int) -> int: + # https://github.com/official-stockfish/Stockfish/blob/sf_16/src/uci.h#L38 + NormalizeToPawnValue = 328 + # https://github.com/official-stockfish/Stockfish/blob/sf_16/src/uci.cpp#L200-L224 + m = min(240, max(ply, 0)) / 64 + a = (((0.38036525 * m + -2.82015070) * m + 23.17882135) * m) + 307.36768407 + b = (((-2.29434733 * m + 13.27689788) * m + -14.26828904) * m) + 63.45318330 + x = min(4000, max(cp * NormalizeToPawnValue / 100, -4000)) + return int(0.5 + 1000 / (1 + math.exp((a - x) / b))) def _sf15_1_wins(cp: int, *, ply: int) -> int: - # https://github.com/official-stockfish/Stockfish/blob/sf_15.1/src/uci.cpp#L200-L224 # https://github.com/official-stockfish/Stockfish/blob/sf_15.1/src/uci.h#L38 NormalizeToPawnValue = 361 + # https://github.com/official-stockfish/Stockfish/blob/sf_15.1/src/uci.cpp#L200-L224 m = min(240, max(ply, 0)) / 64 a = (((-0.58270499 * m + 2.68512549) * m + 15.24638015) * m) + 344.49745382 b = (((-2.65734562 * m + 15.96509799) * m + -20.69040836) * m) + 73.61029937 @@ -703,9 +712,12 @@ def wdl(self, *, model: _WdlModel = "sf", ply: int = 30) -> Wdl: elif model == "sf15": wins = _sf15_wins(self.cp, ply=ply) losses = _sf15_wins(-self.cp, ply=ply) - else: + elif model == "sf15.1": wins = _sf15_1_wins(self.cp, ply=ply) losses = _sf15_1_wins(-self.cp, ply=ply) + else: + wins = _sf16_wins(self.cp, ply=ply) + losses = _sf16_wins(-self.cp, ply=ply) draws = 1000 - wins - losses return Wdl(wins, draws, losses) diff --git a/test.py b/test.py index 17dec2916..50b45cf5c 100755 --- a/test.py +++ b/test.py @@ -3002,6 +3002,7 @@ def test_wdl_model(self): self.assertEqual(chess.engine.Cp(146).wdl(model="sf14", ply=25), chess.engine.Wdl(601, 398, 1)) self.assertEqual(chess.engine.Cp(40).wdl(model="sf15", ply=25), chess.engine.Wdl(58, 937, 5)) self.assertEqual(chess.engine.Cp(100).wdl(model="sf15.1", ply=64), chess.engine.Wdl(497, 503, 0)) + self.assertEqual(chess.engine.Cp(-52).wdl(model="sf16", ply=63), chess.engine.Wdl(0, 932, 68)) @catchAndSkip(FileNotFoundError, "need stockfish") def test_sf_forced_mates(self): From a1f16f828c9d101abb8c7789ee418b06c74d919f Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 8 Jul 2023 17:03:38 -0700 Subject: [PATCH 071/250] Correct documentation of send_game_result method --- chess/engine.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index ae33db688..2b0285aca 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1251,10 +1251,15 @@ async def send_game_result(self, board: chess.Board, winner: Optional[Color] = N """ Sends the engine the result of the game. - UCI engines only recieve the final position of the board. XBoard engines - receive the final moves and a line of the form "result {}", - where is one of "1-0", "0-1", "1/2-1/2", or "*" to indicate white - won, black won, draw, or adjournment, respectively. + XBoard engines receive the final moves and a line of the form + "result {}". The field is one of "1-0", + "0-1", "1/2-1/2", or "*" to indicate white won, black won, draw, + or adjournment, respectively. The field is a description + of the specific reason for the end of the game: "White mates", + "Time forfeiture", "Stalemate", etc. + + UCI engines do not expect end-of-game information and so are not + sent anything. :param board: The final state of the board. :param winner: Optional. Specify the winner of the game. This is useful From 65bf3d09bd0707ac257305f4151eace2cf8db8f0 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 8 Jul 2023 18:44:33 -0700 Subject: [PATCH 072/250] Error on dubious characters in ending messages Curly braces and newlines can allow arbitrary messages to be sent to an engine. Do not allow these characters to be sent in end-of-game messages. Add tests to make sure an exception is raised for invalid characters. --- chess/engine.py | 3 +++ test.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/chess/engine.py b/chess/engine.py index 2b0285aca..41b12033e 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2508,6 +2508,9 @@ async def send_opponent_information(self, *, opponent: Optional[Opponent] = None async def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: class XBoardGameResultCommand(BaseCommand[XBoardProtocol, None]): def start(self, engine: XBoardProtocol) -> None: + if game_ending and any(c in game_ending for c in "{}\n\r"): + raise EngineError(f"invalid line break or curly braces in game ending message: {game_ending!r}") + engine._new(board, engine.game, {}) # Send final moves to engine. outcome = board.outcome(claim_draw=True) diff --git a/test.py b/test.py index fd3b93ed8..4c1bd15c9 100755 --- a/test.py +++ b/test.py @@ -3752,6 +3752,22 @@ async def main(): await protocol.send_game_result(timeout_board, chess.BLACK, "Time forfeiture") mock.assert_done() + error_board = chess.Board() + mock.expect("new") + mock.expect("force") + mock.expect("st 5") + mock.expect("nopost") + mock.expect("easy") + mock.expect("go", ["move e2e4"]) + mock.expect_ping() + result = await protocol.play(error_board, limit, game="error") + self.assertEqual(result.move, error_board.parse_uci("e2e4")) + error_board.push(result.move) + for c in "\n\r{}": + with self.assertRaises(chess.engine.EngineError): + await protocol.send_game_result(error_board, chess.BLACK, f"Time{c}forfeiture") + mock.assert_done() + material_board = chess.Board("k7/8/8/8/8/8/8/K7 b - - 0 1") self.assertTrue(material_board.is_insufficient_material()) mock.expect("new") From ee11a56c96c2105a50111eef9a8a7eb1e5e5e29a Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 13 Jul 2023 01:25:12 -0700 Subject: [PATCH 073/250] Error when XBoard opponent has newline in name Use the configuration machinery to send the opponent's information to the engine instead of using the Opponent class directly. This will make sure that an exception is raised if the opponent's name has newlines in it before send_line() is called. This prevents opponents from injecting commands into the engine. For example, if an opponent sets their name as "Cheat\neasy", then the following commands will be sent to the local engine name Cheat easy which would cause the engine to turn off pondering. Also, add tests to show the change works as expected. --- chess/engine.py | 14 ++++++++------ test.py | 9 +++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 4c24681ee..efcc0f134 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2152,6 +2152,7 @@ def _variant(self, variant: Optional[str]) -> None: def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponent: Optional[Opponent] = None) -> None: self._configure(options) + self._configure(self._opponent_configuration(opponent=opponent)) # Set up starting position. root = board.root() @@ -2172,15 +2173,16 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponen if self.config.get("random"): self.send_line("random") - opponent_name = (opponent.name if opponent else None) or self.target_config.get("name") + opponent_name = self.config.get("name") if opponent_name and self.features.get("name", True): self.send_line(f"name {opponent_name}") - opponent_rating = (opponent.rating if opponent else None) or self.target_config.get("opponent_rating") or 0 - if self.target_config.get("engine_rating") or opponent_rating: - self.send_line(f"rating {self.target_config.get('engine_rating') or 0} {opponent_rating}") + opponent_rating = self.config.get("opponent_rating") + engine_rating = self.config.get("engine_rating") + if engine_rating or opponent_rating: + self.send_line(f"rating {engine_rating or 0} {opponent_rating or 0}") - if (opponent and opponent.is_engine) or (self.target_config.get("computer") if self.config.get("computer") is None else self.config.get("computer")): + if self.config.get("computer"): self.send_line("computer") self.send_line("force") @@ -2518,7 +2520,7 @@ def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine if opponent is None: return {} - opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or 0, + opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or self.target_config.get("engine_rating") or 0, "opponent_rating": opponent.rating or 0, "computer": opponent.is_engine or False} diff --git a/test.py b/test.py index 8cd599474..b109fabf8 100755 --- a/test.py +++ b/test.py @@ -3688,6 +3688,15 @@ async def main(): self.assertEqual(result.move, board.parse_san("e5")) mock.assert_done() + bad_opponent = chess.engine.Opponent("New\nLine", "GM", 1, False) + with self.assertRaises(chess.engine.EngineError): + await protocol.send_opponent_information(opponent=bad_opponent) + mock.assert_done() + + with self.assertRaises(chess.engine.EngineError): + result = await protocol.play(board, limit, game="bad game", opponent=bad_opponent) + mock.assert_done() + asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) From 0dae9d773f18ab10086896969c5842c7caa78f9c Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 15 Jul 2023 05:56:56 -0700 Subject: [PATCH 074/250] Add send_opponent_information() documentation --- chess/engine.py | 10 +++++++++- docs/engine.rst | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index efcc0f134..d60179635 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -449,10 +449,18 @@ class Info(enum.IntFlag): @dataclasses.dataclass class Opponent: """Used to store information about an engine's opponent.""" + name: Optional[str] + """The name of the opponent.""" + title: Optional[str] + """The opponent's title--for example, GM, IM, or BOT.""" + rating: Optional[int] + """The opponent's ELO rating.""" + is_engine: Optional[bool] + """Whether the opponent is a chess engine/computer program.""" class PovScore: @@ -1158,7 +1166,7 @@ async def send_opponent_information(self, *, opponent: Optional[Opponent] = None method should be called before the first move of a game--i.e., the first call to :func:`chess.engine.Protocol.play()`. - :param opponent: Optional. The opponent's information. + :param opponent: Optional. An instance of :class:`chess.engine.Opponent` that has the opponent's information. :param engine_rating: Optional. This engine's own rating. Only used by XBoard engines. """ diff --git a/docs/engine.rst b/docs/engine.rst index 08f8f8f5e..556d64793 100644 --- a/docs/engine.rst +++ b/docs/engine.rst @@ -70,6 +70,12 @@ Example: Let Stockfish play against itself, 100 milliseconds per move. .. autoclass:: chess.engine.PlayResult :members: +.. autoclass:: chess.engine.Protocol + :members: send_opponent_information + +.. autoclass:: chess.engine.Opponent + :members: + Analysing and evaluating a position ----------------------------------- From 0fcee3568956feaba9f96cb1a906b4a68c83c9ab Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 15 Jul 2023 05:58:49 -0700 Subject: [PATCH 075/250] Add send_game_result() documentation Also, correct formatting and spelling. --- chess/engine.py | 11 ++++++----- docs/engine.rst | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index d60179635..30618d829 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1280,9 +1280,9 @@ async def send_game_result(self, board: chess.Board, winner: Optional[Color] = N Sends the engine the result of the game. XBoard engines receive the final moves and a line of the form - "result {}". The field is one of "1-0", - "0-1", "1/2-1/2", or "*" to indicate white won, black won, draw, - or adjournment, respectively. The field is a description + ``result {}``. The ```` field is one of ``1-0``, + ``0-1``, ``1/2-1/2``, or ``*`` to indicate white won, black won, draw, + or adjournment, respectively. The ```` field is a description of the specific reason for the end of the game: "White mates", "Time forfeiture", "Stalemate", etc. @@ -1292,9 +1292,10 @@ async def send_game_result(self, board: chess.Board, winner: Optional[Color] = N :param board: The final state of the board. :param winner: Optional. Specify the winner of the game. This is useful if the result of the game is not evident from the board--e.g., time - forfeiture or draw by agreement. + forfeiture or draw by agreement. If not ``None``, this parameter + overrides any winner derivable from the board. :param game_ending: Optional. Text describing the reason for the game - ending. Similarly to the winner paramter, this overrides any game + ending. Similarly to the winner parameter, this overrides any game result derivable from the board. :param game_complete: Optional. Whether the game reached completion. """ diff --git a/docs/engine.rst b/docs/engine.rst index 556d64793..02dd4548f 100644 --- a/docs/engine.rst +++ b/docs/engine.rst @@ -76,6 +76,9 @@ Example: Let Stockfish play against itself, 100 milliseconds per move. .. autoclass:: chess.engine.Opponent :members: +.. autoclass:: chess.engine.Protocol + :members: send_game_result + Analysing and evaluating a position ----------------------------------- From 53e92b445b9340368b1791843e24a8975fb602d5 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 25 Jul 2023 21:16:14 +0200 Subject: [PATCH 076/250] Document potentially surprising time complexities (closes #1000) --- chess/pgn.py | 50 +++++++++++++++++++++++++++++++++++++++++++++----- docs/pgn.rst | 4 ++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 1f99f6506..f6783585c 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -215,6 +215,8 @@ def board(self) -> chess.Board: ``Variant``) unless the ``FEN`` header tag is set. It's a copy, so modifying the board will not alter the game. + + Complexity is `O(n)`. """ @abc.abstractmethod @@ -226,11 +228,15 @@ def ply(self) -> int: Usually this is equal to the number of parent nodes, but it may be more if the game was started from a custom position. + + Complexity is `O(n)`. """ def turn(self) -> Color: """ Gets the color to move at this node. See :data:`chess.Board.turn`. + + Complexity is `O(n)`. """ return self.ply() % 2 == 0 @@ -241,13 +247,21 @@ def root(self) -> GameNode: return node def game(self) -> Game: - """Gets the root node, i.e., the game.""" + """ + Gets the root node, i.e., the game. + + Complexity is `O(n)`. + """ root = self.root() assert isinstance(root, Game), "GameNode not rooted in Game" return root def end(self) -> GameNode: - """Follows the main variation to the end and returns the last node.""" + """ + Follows the main variation to the end and returns the last node. + + Complexity is `O(n)`. + """ node = self while node.variations: @@ -256,7 +270,11 @@ def end(self) -> GameNode: return node def is_end(self) -> bool: - """Checks if this node is the last node in the current variation.""" + """ + Checks if this node is the last node in the current variation. + + Complexity is `O(1)`. + """ return not self.variations def starts_variation(self) -> bool: @@ -267,6 +285,8 @@ def starts_variation(self) -> bool: For example, in ``1. e4 e5 (1... c5 2. Nf3) 2. Nf3``, the node holding 1... c5 starts a variation. + + Complexity is `O(1)`. """ if not self.parent or not self.parent.variations: return False @@ -274,7 +294,11 @@ def starts_variation(self) -> bool: return self.parent.variations[0] != self def is_mainline(self) -> bool: - """Checks if the node is in the mainline of the game.""" + """ + Checks if the node is in the mainline of the game. + + Complexity is `O(n)`. + """ node = self while node.parent: @@ -291,6 +315,8 @@ def is_main_variation(self) -> bool: """ Checks if this node is the first variation from the point of view of its parent. The root node is also in the main variation. + + Complexity is `O(1)`. """ if not self.parent: return True @@ -367,6 +393,8 @@ def next(self) -> Optional[ChildNode]: """ Returns the first node of the mainline after this node, or ``None`` if this node does not have any children. + + Complexity is `O(1)`. """ return self.variations[0] if self.variations else None @@ -404,6 +432,8 @@ def eval(self) -> Optional[chess.engine.PovScore]: """ Parses the first valid ``[%eval ...]`` annotation in the comment of this node, if any. + + Complexity is `O(n)`. """ match = EVAL_REGEX.search(self.comment) if not match: @@ -428,6 +458,8 @@ def eval_depth(self) -> Optional[int]: """ Parses the first valid ``[%eval ...]`` annotation in the comment of this node and returns the corresponding depth, if any. + + Complexity is `O(1)`. """ match = EVAL_REGEX.search(self.comment) return int(match.group("depth")) if match and match.group("depth") else None @@ -670,6 +702,8 @@ def san(self) -> str: See :func:`chess.Board.san()`. Do not call this on the root node. + + Complexity is `O(n)`. """ return self.parent.board().san(self.move) @@ -679,11 +713,17 @@ def uci(self, *, chess960: Optional[bool] = None) -> str: See :func:`chess.Board.uci()`. Do not call this on the root node. + + Complexity is `O(n)`. """ return self.parent.board().uci(self.move, chess960=chess960) def end(self) -> ChildNode: - """Follows the main variation to the end and returns the last node.""" + """ + Follows the main variation to the end and returns the last node. + + Complexity is `O(n)`. + """ return typing.cast(ChildNode, super().end()) def _accept_node(self, parent_board: chess.Board, visitor: BaseVisitor[ResultT]) -> None: diff --git a/docs/pgn.rst b/docs/pgn.rst index 9ebe96594..dd5a6fa47 100644 --- a/docs/pgn.rst +++ b/docs/pgn.rst @@ -48,6 +48,10 @@ position of the game. The tree consists of one root node nodes (:class:`~chess.pgn.ChildNode`). Both extend :class:`~chess.pgn.GameNode`. +.. note:: Some basic methods have complexity `O(n)` for a game with n moves. + When following a variation, it is often more efficient to use visitors + or incrementally update state (like board, ply counter, or turn). + .. autoclass:: chess.pgn.GameNode :members: From 59a5233da0f601e18df04a3b4532d54fd252e8e9 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 25 Jul 2023 21:22:54 +0200 Subject: [PATCH 077/250] Update Stockfish 11 download URLs (fixes #1019) --- .github/workflows/setup-ubuntu-latest.sh | 2 +- .github/workflows/setup-windows-latest.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/setup-ubuntu-latest.sh b/.github/workflows/setup-ubuntu-latest.sh index de1d567fd..8954c8f0c 100755 --- a/.github/workflows/setup-ubuntu-latest.sh +++ b/.github/workflows/setup-ubuntu-latest.sh @@ -1,7 +1,7 @@ #!/bin/sh -e # Stockfish -wget https://stockfish.s3.amazonaws.com/stockfish-11-linux.zip +wget https://files.stockfishchess.org/archive/Stockfish%2011/stockfish-11-linux.zip unzip stockfish-11-linux.zip mkdir -p bin cp stockfish-11-linux/Linux/stockfish_20011801_x64_bmi2 bin/stockfish diff --git a/.github/workflows/setup-windows-latest.sh b/.github/workflows/setup-windows-latest.sh index 3ae917a5c..685ead65a 100755 --- a/.github/workflows/setup-windows-latest.sh +++ b/.github/workflows/setup-windows-latest.sh @@ -2,7 +2,7 @@ echo Download ... choco install wget -wget https://stockfishchess.org/files/stockfish-11-win.zip +wget https://files.stockfishchess.org/archive/Stockfish%2011/stockfish-11-win.zip echo Unzip .. 7z e stockfish-11-win.zip stockfish-11-win/Windows/*.exe From 34de67dfd285e36f152a6e4eca0ce9f32ab82328 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 25 Jul 2023 22:29:10 +0200 Subject: [PATCH 078/250] Prepare changelog for next release --- CHANGELOG.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2580c841c..0e5872ed4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,38 @@ Changelog for python-chess ========================== +Upcoming in the next release +---------------------------- + +New features: + +* Use ``chess.engine.Opponent`` to send opponent information to engines. +* Inform engines about the game result using + ``chess.engine.Protocol.send_game_result()``. +* Add ``chess.engine.Limit.clock_id``. +* Add ``chess.svg.board(..., borders=True)``. +* Avoid rendering background behind SVG boards to better support transparency. +* Add ``chess.pgn.BaseVisitor.begin_parse_san()``. +* Introduce new distance metrics ``chess.square_manhattan_distance()`` and + ``chess.square_knight_distance()``. + +Bugfixes: + +* Fix ``chess.pgn.GameNode.eval()`` sometimes off by one centipawn. +* Fix handling of additional spaces between UCI option tokens. +* Handle implicit XBoard engine resignation via output like + ``0-1 {White resigns}``. + +Changes: + +* Add model ``sf16`` for ``chess.engine.Score.wdl()``, the new default. +* Update ``lichess`` WDL model. +* Keep PGN headers that do not belong to the Seven Tag Roster in insertion + order. +* Halve the number of open file descriptors maintained by tablebases + and opening books. +* Reduce verbosity of logged ``chess.pgn`` errors. + New in v1.9.4 (22nd Dec 2022) ----------------------------- From 41b27bb099169c6b36590e1bc9b690a2de8f9a2a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 18:30:59 +0200 Subject: [PATCH 079/250] Bump 1.10.0 --- CHANGELOG.rst | 4 ++-- chess/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0e5872ed4..a44b2b070 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,8 @@ Changelog for python-chess ========================== -Upcoming in the next release ----------------------------- +New in v1.10.0 (27th Jul 2023) +------------------------------ New features: diff --git a/chess/__init__.py b/chess/__init__.py index 980dc34b4..6c0cf9c94 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -27,7 +27,7 @@ __email__ = "niklas.fiekas@backscattering.de" -__version__ = "1.9.4" +__version__ = "1.10.0" import collections import copy From cfda9c0f70697e6c17f71ffa1d1381c5067dae62 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 18:32:48 +0200 Subject: [PATCH 080/250] Test Python 3.11 using tox --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 3eeb764ba..1b103fd6c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py37,py38,py39,py310 +envlist = py37,py38,py39,py310,py311 [testenv] passenv = LD_LIBRARY_PATH From 23e43177cc979660907814540e210ce0ea45c43b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 19:29:50 +0200 Subject: [PATCH 081/250] Make flake8 happy --- chess/__init__.py | 2 +- chess/engine.py | 8 ++++---- chess/variant.py | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 6c0cf9c94..b87e3cbec 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -240,7 +240,7 @@ def square_knight_distance(a: Square, b: Square) -> int: elif dx == dy == 2: return 4 elif dx == dy == 1: - if BB_SQUARES[a] & BB_CORNERS or BB_SQUARES[b] & BB_CORNERS: # Special case only for corner squares + if BB_SQUARES[a] & BB_CORNERS or BB_SQUARES[b] & BB_CORNERS: # Special case only for corner squares return 4 m = math.ceil(max(dx / 2, dy / 2, (dx + dy) / 3)) diff --git a/chess/engine.py b/chess/engine.py index 30618d829..cab9d5d2c 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2181,7 +2181,7 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponen if self.config.get("random"): self.send_line("random") - + opponent_name = self.config.get("name") if opponent_name and self.features.get("name", True): self.send_line(f"name {opponent_name}") @@ -2532,7 +2532,7 @@ def _opponent_configuration(self, *, opponent: Optional[Opponent] = None, engine opponent_info: Dict[str, Union[int, bool, str]] = {"engine_rating": engine_rating or self.target_config.get("engine_rating") or 0, "opponent_rating": opponent.rating or 0, "computer": opponent.is_engine or False} - + if opponent.name and self.features.get("name", True): opponent_info["name"] = f"{opponent.title or ''} {opponent.name}".strip() @@ -2548,7 +2548,7 @@ def start(self, engine: XBoardProtocol) -> None: raise EngineError(f"invalid line break or curly braces in game ending message: {game_ending!r}") engine._new(board, engine.game, {}) # Send final moves to engine. - + outcome = board.outcome(claim_draw=True) if not game_complete: @@ -2966,7 +2966,7 @@ def send_opponent_information(self, *, opponent: Optional[Opponent] = None, engi self.timeout) future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() - + def ping(self) -> None: with self._not_shut_down(): coro = asyncio.wait_for(self.protocol.ping(), self.timeout) diff --git a/chess/variant.py b/chess/variant.py index cd1670480..31cdea287 100644 --- a/chess/variant.py +++ b/chess/variant.py @@ -17,7 +17,6 @@ from __future__ import annotations import chess -import copy import itertools from typing import Dict, Generic, Hashable, Iterable, Iterator, List, Optional, Type, TypeVar, Union From 8ede90039228a78e0d74c3b07fb3cbaacea752f6 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 19:34:26 +0200 Subject: [PATCH 082/250] PyPI has removed GPG signatures --- release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.py b/release.py index 099dd4a98..d27ddf04e 100755 --- a/release.py +++ b/release.py @@ -99,7 +99,7 @@ def pypi(): system("rm -rf build") system("python3 setup.py sdist bdist_wheel") system("twine check dist/*") - system("twine upload --skip-existing --sign dist/*") + system("twine upload --skip-existing") def github_release(tagname): From 1cca86ff8fcf6ee587d9a138fd774d1b762ed0e6 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 19:39:46 +0200 Subject: [PATCH 083/250] Remove redundant license headers --- chess/__init__.py | 16 ---------------- chess/engine.py | 16 ---------------- chess/gaviota.py | 17 ----------------- chess/pgn.py | 16 ---------------- chess/polyglot.py | 16 ---------------- chess/svg.py | 20 -------------------- chess/syzygy.py | 16 ---------------- chess/variant.py | 16 ---------------- setup.py | 16 ---------------- test.py | 16 ---------------- 10 files changed, 165 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index b87e3cbec..a41f38501 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -1,19 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - """ A chess library with move generation and validation, Polyglot opening book probing, PGN reading and writing, diff --git a/chess/engine.py b/chess/engine.py index cab9d5d2c..37b7715fd 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1,19 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - from __future__ import annotations import abc diff --git a/chess/gaviota.py b/chess/gaviota.py index 454949795..c2439728f 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -1,20 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2015 Jean-Noël Avila -# Copyright (C) 2015-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - from __future__ import annotations import ctypes diff --git a/chess/pgn.py b/chess/pgn.py index f6783585c..edeab84a3 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1,19 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - from __future__ import annotations import abc diff --git a/chess/polyglot.py b/chess/polyglot.py index 39270c129..7d9e425ea 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -1,19 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - from __future__ import annotations import chess diff --git a/chess/svg.py b/chess/svg.py index 94ae21569..3e034ce30 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -1,23 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2016-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# Piece vector graphics are copyright (C) Colin M.L. Burnett -# and also licensed under the -# GNU General Public License. - from __future__ import annotations import math diff --git a/chess/syzygy.py b/chess/syzygy.py index 2d835b200..fd9d80890 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1,19 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - from __future__ import annotations import collections diff --git a/chess/variant.py b/chess/variant.py index 31cdea287..e81d0aa72 100644 --- a/chess/variant.py +++ b/chess/variant.py @@ -1,19 +1,3 @@ -# This file is part of the python-chess library. -# Copyright (C) 2016-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - from __future__ import annotations import chess diff --git a/setup.py b/setup.py index bc6a8af51..09675868e 100755 --- a/setup.py +++ b/setup.py @@ -1,21 +1,5 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . import os import platform diff --git a/test.py b/test.py index b109fabf8..d25dd75ad 100755 --- a/test.py +++ b/test.py @@ -1,20 +1,4 @@ #!/usr/bin/env python3 -# -# This file is part of the python-chess library. -# Copyright (C) 2012-2021 Niklas Fiekas -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . import asyncio import copy From ff1a974408abf6da882b633a19e9a340fd21b3e2 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 19:42:27 +0200 Subject: [PATCH 084/250] Test WDL consistency under all models --- test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index d25dd75ad..6419eb89f 100755 --- a/test.py +++ b/test.py @@ -2948,9 +2948,10 @@ def test_score_ordering(self): self.assertEqual(i >= j, a >= b) self.assertEqual(i < j, a.score(mate_score=100000) < b.score(mate_score=100000)) - self.assertTrue(not (i < j) or a.wdl().expectation() <= b.wdl().expectation()) - self.assertTrue(not (i < j) or a.wdl().winning_chance() <= b.wdl().winning_chance()) - self.assertTrue(not (i < j) or a.wdl().losing_chance() >= b.wdl().losing_chance()) + for model in ["sf12", "sf14", "sf15", "sf15.1", "sf16"]: + self.assertTrue(not (i < j) or a.wdl(model=model).expectation() <= b.wdl(model=model).expectation()) + self.assertTrue(not (i < j) or a.wdl(model=model).winning_chance() <= b.wdl(model=model).winning_chance()) + self.assertTrue(not (i < j) or a.wdl(model=model).losing_chance() >= b.wdl(model=model).losing_chance()) def test_score(self): # Negation. From 9ba8b68d789a6fb7f96c3640cbc7c1c3667cb119 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 19:51:35 +0200 Subject: [PATCH 085/250] Drop support for Python 3.7 (#463) --- .github/workflows/test.yml | 2 +- chess/polyglot.py | 4 ++-- chess/syzygy.py | 2 +- setup.py | 3 +-- tox.ini | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 95e9a3728..e06db4221 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/chess/polyglot.py b/chess/polyglot.py index 7d9e425ea..92704e6a4 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -333,8 +333,8 @@ def __init__(self, filename: PathLike) -> None: raise IOError(f"invalid file size: ensure {filename!r} is a valid polyglot opening book") try: - # Python 3.8 - self.mmap.madvise(mmap.MADV_RANDOM) # type: ignore + # Linux + self.mmap.madvise(mmap.MADV_RANDOM) except AttributeError: pass diff --git a/chess/syzygy.py b/chess/syzygy.py index fd9d80890..af375b5da 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -596,7 +596,7 @@ def init_mmap(self) -> None: raise IOError(f"invalid file size: ensure {self.path!r} is a valid syzygy tablebase file") try: - # Python 3.8 + # Linux data.madvise(mmap.MADV_RANDOM) except AttributeError: pass diff --git a/setup.py b/setup.py index 09675868e..ed3d8b0bf 100755 --- a/setup.py +++ b/setup.py @@ -65,7 +65,7 @@ def read_description(): package_data={ "chess": ["py.typed"], }, - python_requires=">=3.7", + python_requires=">=3.8", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -73,7 +73,6 @@ def read_description(): "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", diff --git a/tox.ini b/tox.ini index 1b103fd6c..665e9f38b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py37,py38,py39,py310,py311 +envlist = py38,py39,py310,py311 [testenv] passenv = LD_LIBRARY_PATH @@ -10,7 +10,7 @@ commands = python test.py --verbose python -m doctest README.rst --verbose -[testenv:{py37,py38,py39}] +[testenv:{py38,py39}] passenv = LD_LIBRARY_PATH whitelist_externals = stockfish From 85816125b4936ebfd0fd90a2cbddda747c7eeafd Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 19:52:02 +0200 Subject: [PATCH 086/250] Try mypy also under Python 3.10 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e06db4221..184092752 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.9", "3.11"] + python-version: ["3.9", "3.10", "3.11"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 From 8b9e1481568e35802c733140ef2303361976e764 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:05:07 +0200 Subject: [PATCH 087/250] fixup! Drop support for Python 3.7 (#463) --- chess/polyglot.py | 5 ++++- chess/syzygy.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/chess/polyglot.py b/chess/polyglot.py index 92704e6a4..ac339902c 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -312,6 +312,9 @@ def size(self) -> int: def close(self) -> None: pass + def madvise(self, option: int, start: int = ..., length: int = ...) -> None: + pass + def _randint(rng: Optional[random.Random], a: int, b: int) -> int: return random.randint(a, b) if rng is None else rng.randint(a, b) @@ -333,7 +336,7 @@ def __init__(self, filename: PathLike) -> None: raise IOError(f"invalid file size: ensure {filename!r} is a valid polyglot opening book") try: - # Linux + # Unix self.mmap.madvise(mmap.MADV_RANDOM) except AttributeError: pass diff --git a/chess/syzygy.py b/chess/syzygy.py index af375b5da..96a17e921 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -596,7 +596,7 @@ def init_mmap(self) -> None: raise IOError(f"invalid file size: ensure {self.path!r} is a valid syzygy tablebase file") try: - # Linux + # Unix data.madvise(mmap.MADV_RANDOM) except AttributeError: pass From 6fbb309554e7aaaa450432972a66a1879fcbfe86 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:05:31 +0200 Subject: [PATCH 088/250] Unconditionally use typing.Literal --- chess/__init__.py | 15 +++++---------- chess/engine.py | 19 +++++++------------ chess/pgn.py | 13 +++---------- chess/variant.py | 4 ++-- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index a41f38501..0604cec54 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -22,14 +22,9 @@ import itertools import typing -from typing import ClassVar, Callable, Counter, Dict, Generic, Hashable, Iterable, Iterator, List, Mapping, Optional, SupportsInt, Tuple, Type, TypeVar, Union +from typing import ClassVar, Callable, Counter, Dict, Generic, Hashable, Iterable, Iterator, List, Literal, Mapping, Optional, SupportsInt, Tuple, Type, TypeVar, Union -try: - from typing import Literal - _EnPassantSpec = Literal["legal", "fen", "xfen"] -except ImportError: - # Before Python 3.8. - _EnPassantSpec = str # type: ignore +EnPassantSpec = Literal["legal", "fen", "xfen"] Color = bool @@ -2394,7 +2389,7 @@ def has_legal_en_passant(self) -> bool: """Checks if there is a legal en passant capture.""" return self.ep_square is not None and any(self.generate_legal_ep()) - def fen(self, *, shredder: bool = False, en_passant: _EnPassantSpec = "legal", promoted: Optional[bool] = None) -> str: + def fen(self, *, shredder: bool = False, en_passant: EnPassantSpec = "legal", promoted: Optional[bool] = None) -> str: """ Gets a FEN representation of the position. @@ -2426,7 +2421,7 @@ def fen(self, *, shredder: bool = False, en_passant: _EnPassantSpec = "legal", p str(self.fullmove_number) ]) - def shredder_fen(self, *, en_passant: _EnPassantSpec = "legal", promoted: Optional[bool] = None) -> str: + def shredder_fen(self, *, en_passant: EnPassantSpec = "legal", promoted: Optional[bool] = None) -> str: return " ".join([ self.epd(shredder=True, en_passant=en_passant, promoted=promoted), str(self.halfmove_clock), @@ -2662,7 +2657,7 @@ def _epd_operations(self, operations: Mapping[str, Union[None, str, int, float, return "".join(epd) - def epd(self, *, shredder: bool = False, en_passant: _EnPassantSpec = "legal", promoted: Optional[bool] = None, **operations: Union[None, str, int, float, Move, Iterable[Move]]) -> str: + def epd(self, *, shredder: bool = False, en_passant: EnPassantSpec = "legal", promoted: Optional[bool] = None, **operations: Union[None, str, int, float, Move, Iterable[Move]]) -> str: """ Gets an EPD representation of the current position. diff --git a/chess/engine.py b/chess/engine.py index 37b7715fd..144fbb649 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -24,14 +24,9 @@ from chess import Color from types import TracebackType -from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Mapping, MutableMapping, Optional, Tuple, Type, TypeVar, Union +from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypeVar, Union -try: - from typing import Literal - _WdlModel = Literal["sf", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] -except ImportError: - # Before Python 3.8. - _WdlModel = str # type: ignore +WdlModel = Literal["sf", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] T = TypeVar("T") @@ -476,7 +471,7 @@ def is_mate(self) -> bool: """Tests if this is a mate score.""" return self.relative.is_mate() - def wdl(self, *, model: _WdlModel = "sf", ply: int = 30) -> PovWdl: + def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> PovWdl: """See :func:`~chess.engine.Score.wdl()`.""" return PovWdl(self.relative.wdl(model=model, ply=ply), self.turn) @@ -553,7 +548,7 @@ def is_mate(self) -> bool: return self.mate() is not None @abc.abstractmethod - def wdl(self, *, model: _WdlModel = "sf", ply: int = 30) -> Wdl: + def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl: """ Returns statistics for the expected outcome of this game, based on a *model*, given that this score is reached at *ply*. @@ -699,7 +694,7 @@ def mate(self) -> None: def score(self, *, mate_score: Optional[int] = None) -> int: return self.cp - def wdl(self, *, model: _WdlModel = "sf", ply: int = 30) -> Wdl: + def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl: if model == "lichess": wins = _lichess_raw_wins(max(-1000, min(self.cp, 1000))) losses = 1000 - wins @@ -758,7 +753,7 @@ def score(self, *, mate_score: Optional[int] = None) -> Optional[int]: else: return -mate_score - self.moves - def wdl(self, *, model: _WdlModel = "sf", ply: int = 30) -> Wdl: + def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl: if model == "lichess": cp = (21 - min(10, abs(self.moves))) * 100 wins = _lichess_raw_wins(cp) @@ -795,7 +790,7 @@ def score(self, *, mate_score: Optional[int] = None) -> Optional[int]: ... def score(self, *, mate_score: Optional[int] = None) -> Optional[int]: return mate_score - def wdl(self, *, model: _WdlModel = "sf", ply: int = 30) -> Wdl: + def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl: return Wdl(1000, 0, 0) def __neg__(self) -> Mate: diff --git a/chess/pgn.py b/chess/pgn.py index edeab84a3..ae22afaf6 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -11,16 +11,9 @@ import chess.engine import chess.svg -from typing import Any, Callable, Dict, Generic, Iterable, Iterator, List, Mapping, MutableMapping, Set, TextIO, Tuple, Type, TypeVar, Optional, Union +from typing import Any, Callable, Dict, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Set, TextIO, Tuple, Type, TypeVar, Optional, Union from chess import Color, Square -try: - from typing import Literal - _TrueLiteral = Literal[True] -except ImportError: - # Before Python 3.8. - _TrueLiteral = bool # type: ignore - LOGGER = logging.getLogger(__name__) @@ -1289,7 +1282,7 @@ def result(self) -> chess.Board: return self.board -class SkipVisitor(BaseVisitor[_TrueLiteral]): +class SkipVisitor(BaseVisitor[Literal[True]]): """Skips a game.""" def begin_game(self) -> SkipType: @@ -1301,7 +1294,7 @@ def end_headers(self) -> SkipType: def begin_variation(self) -> SkipType: return SKIP - def result(self) -> _TrueLiteral: + def result(self) -> Literal[True]: return True diff --git a/chess/variant.py b/chess/variant.py index e81d0aa72..6160696a2 100644 --- a/chess/variant.py +++ b/chess/variant.py @@ -762,7 +762,7 @@ def set_fen(self, fen: str) -> None: self.remaining_checks[chess.WHITE] = wc self.remaining_checks[chess.BLACK] = bc - def epd(self, shredder: bool = False, en_passant: chess._EnPassantSpec = "legal", promoted: Optional[bool] = None, **operations: Union[None, str, int, float, chess.Move, Iterable[chess.Move]]) -> str: + def epd(self, shredder: bool = False, en_passant: chess.EnPassantSpec = "legal", promoted: Optional[bool] = None, **operations: Union[None, str, int, float, chess.Move, Iterable[chess.Move]]) -> str: epd = [super().epd(shredder=shredder, en_passant=en_passant, promoted=promoted), "{:d}+{:d}".format(max(self.remaining_checks[chess.WHITE], 0), max(self.remaining_checks[chess.BLACK], 0))] @@ -1019,7 +1019,7 @@ def board_fen(self, promoted: Optional[bool] = None) -> str: promoted = True return super().board_fen(promoted=promoted) - def epd(self, shredder: bool = False, en_passant: chess._EnPassantSpec = "legal", promoted: Optional[bool] = None, **operations: Union[None, str, int, float, chess.Move, Iterable[chess.Move]]) -> str: + def epd(self, shredder: bool = False, en_passant: chess.EnPassantSpec = "legal", promoted: Optional[bool] = None, **operations: Union[None, str, int, float, chess.Move, Iterable[chess.Move]]) -> str: epd = super().epd(shredder=shredder, en_passant=en_passant, promoted=promoted) board_part, info_part = epd.split(" ", 1) return f"{board_part}[{str(self.pockets[chess.WHITE]).upper()}{self.pockets[chess.BLACK]}] {info_part}" From 6dcc975d7ca599a8288c1b9435e1a161221aea49 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:06:55 +0200 Subject: [PATCH 089/250] Unconditionally use TypedDict --- chess/engine.py | 62 +++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 144fbb649..75ee9de58 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -328,41 +328,37 @@ def __repr__(self) -> str: if getattr(self, attr) is not None)) -try: - class InfoDict(typing.TypedDict, total=False): - """ - Dictionary of aggregated information sent by the engine. +class InfoDict(typing.TypedDict, total=False): + """ + Dictionary of aggregated information sent by the engine. - Commonly used keys are: ``score`` (a :class:`~chess.engine.PovScore`), - ``pv`` (a list of :class:`~chess.Move` objects), ``depth``, - ``seldepth``, ``time`` (in seconds), ``nodes``, ``nps``, ``multipv`` - (``1`` for the mainline). + Commonly used keys are: ``score`` (a :class:`~chess.engine.PovScore`), + ``pv`` (a list of :class:`~chess.Move` objects), ``depth``, + ``seldepth``, ``time`` (in seconds), ``nodes``, ``nps``, ``multipv`` + (``1`` for the mainline). - Others: ``tbhits``, ``currmove``, ``currmovenumber``, ``hashfull``, - ``cpuload``, ``refutation``, ``currline``, ``ebf`` (effective branching factor), - ``wdl`` (a :class:`~chess.engine.PovWdl`), and ``string``. - """ - score: PovScore - pv: List[chess.Move] - depth: int - seldepth: int - time: float - nodes: int - nps: int - tbhits: int - multipv: int - currmove: chess.Move - currmovenumber: int - hashfull: int - cpuload: int - refutation: Dict[chess.Move, List[chess.Move]] - currline: Dict[int, List[chess.Move]] - ebf: float - wdl: PovWdl - string: str -except AttributeError: - # Before Python 3.8. - InfoDict = dict # type: ignore + Others: ``tbhits``, ``currmove``, ``currmovenumber``, ``hashfull``, + ``cpuload``, ``refutation``, ``currline``, ``ebf`` (effective branching factor), + ``wdl`` (a :class:`~chess.engine.PovWdl`), and ``string``. + """ + score: PovScore + pv: List[chess.Move] + depth: int + seldepth: int + time: float + nodes: int + nps: int + tbhits: int + multipv: int + currmove: chess.Move + currmovenumber: int + hashfull: int + cpuload: int + refutation: Dict[chess.Move, List[chess.Move]] + currline: Dict[int, List[chess.Move]] + ebf: float + wdl: PovWdl + string: str class PlayResult: From 8214d9757da593c71ad13a1bcb933393125d5937 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:23:14 +0200 Subject: [PATCH 090/250] Remove PollingChildWatcher --- chess/engine.py | 45 +++++---------------------------------------- 1 file changed, 5 insertions(+), 40 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 75ee9de58..6fac0c602 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -108,46 +108,11 @@ def _init_watcher(self) -> asyncio.AbstractChildWatcher: pass if threading.current_thread() is threading.main_thread(): - try: - watcher = asyncio.ThreadedChildWatcher() - LOGGER.debug("Using ThreadedChildWatcher") - return watcher - except AttributeError: - # Before Python 3.8. - LOGGER.debug("Using SafeChildWatcher") - return asyncio.SafeChildWatcher() - - class PollingChildWatcher(asyncio.SafeChildWatcher): - _loop: Optional[asyncio.AbstractEventLoop] - _callbacks: Dict[int, Any] - - def __init__(self) -> None: - super().__init__() - self._poll_handle: Optional[asyncio.Handle] = None - self._poll_delay = 0.001 - - def attach_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None: - assert loop is None or isinstance(loop, asyncio.AbstractEventLoop) - - if self._loop is not None and loop is None and self._callbacks: - warnings.warn("A loop is being detached from a child watcher with pending handlers", RuntimeWarning) - - if self._poll_handle is not None: - self._poll_handle.cancel() - - self._loop = loop - if self._loop is not None: - self._poll_handle = self._loop.call_soon(self._poll) - self._do_waitpid_all() # type: ignore - - def _poll(self) -> None: - if self._loop: - self._do_waitpid_all() # type: ignore - self._poll_delay = min(self._poll_delay * 2, 1.0) - self._poll_handle = self._loop.call_later(self._poll_delay, self._poll) - - LOGGER.debug("Using PollingChildWatcher") - return PollingChildWatcher() + LOGGER.debug("Using SafeChildWatcher") + return asyncio.SafeChildWatcher() + else: + LOGGER.debug("Using ThreadedChildWatcher") + return asyncio.ThreadedChildWatcher() def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: bool = False, _policy_lock: threading.Lock = threading.Lock()) -> T: From 7acc7cf603dee1e129957a68b1584e7cc9a9536a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:33:46 +0200 Subject: [PATCH 091/250] Stop using chess.engine.EventLoopPolicy --- chess/engine.py | 80 +-------------------------- docs/engine.rst | 6 -- examples/bratko_kopec/bratko_kopec.py | 1 - fuzz/engine.py | 1 - test.py | 17 ------ 5 files changed, 2 insertions(+), 103 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 6fac0c602..6958479f9 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -42,77 +42,8 @@ MANAGED_OPTIONS = ["uci_chess960", "uci_variant", "multipv", "ponder"] -class EventLoopPolicy(asyncio.AbstractEventLoopPolicy): - """ - An event loop policy for thread-local event loops and child watchers. - Ensures each event loop is capable of spawning and watching subprocesses, - even when not running on the main thread. - - Windows: Uses :class:`~asyncio.ProactorEventLoop`. - - Unix: Uses :class:`~asyncio.SelectorEventLoop`. If available, - :class:`~asyncio.PidfdChildWatcher` is used to detect subprocess - termination (Python 3.9+ on Linux 5.3+). Otherwise, the default child - watcher is used on the main thread and relatively slow eager polling - is used on all other threads. - """ - class _Local(threading.local): - loop: Optional[asyncio.AbstractEventLoop] = None - set_called = False - watcher: Optional[asyncio.AbstractChildWatcher] = None - - def __init__(self) -> None: - self._local = self._Local() - - def get_event_loop(self) -> asyncio.AbstractEventLoop: - if self._local.loop is None and not self._local.set_called and threading.current_thread() is threading.main_thread(): - self.set_event_loop(self.new_event_loop()) - if self._local.loop is None: - raise RuntimeError(f"no current event loop in thread {threading.current_thread().name!r}") - return self._local.loop - - def set_event_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None: - assert loop is None or isinstance(loop, asyncio.AbstractEventLoop) - self._local.set_called = True - self._local.loop = loop - if self._local.watcher is not None: - self._local.watcher.attach_loop(loop) - - def new_event_loop(self) -> asyncio.AbstractEventLoop: - return asyncio.ProactorEventLoop() if sys.platform == "win32" else asyncio.SelectorEventLoop() # type: ignore - - def get_child_watcher(self) -> asyncio.AbstractChildWatcher: - if self._local.watcher is None: - self._local.watcher = self._init_watcher() - self._local.watcher.attach_loop(self._local.loop) - return self._local.watcher - - def set_child_watcher(self, watcher: Optional[asyncio.AbstractChildWatcher]) -> None: - assert watcher is None or isinstance(watcher, asyncio.AbstractChildWatcher) - if self._local.watcher is not None: - self._local.watcher.close() - self._local.watcher = watcher - - def _init_watcher(self) -> asyncio.AbstractChildWatcher: - if sys.platform == "win32": - raise NotImplementedError - - try: - os.close(os.pidfd_open(os.getpid())) - watcher: asyncio.AbstractChildWatcher = asyncio.PidfdChildWatcher() - LOGGER.debug("Using PidfdChildWatcher") - return watcher - except (AttributeError, OSError): - # Before Python 3.9 or before Linux 5.3 or the syscall is not - # permitted. - pass - - if threading.current_thread() is threading.main_thread(): - LOGGER.debug("Using SafeChildWatcher") - return asyncio.SafeChildWatcher() - else: - LOGGER.debug("Using ThreadedChildWatcher") - return asyncio.ThreadedChildWatcher() +# No longer needed, but alias kept around for compatibility. +EventLoopPolicy = asyncio.DefaultEventLoopPolicy def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: bool = False, _policy_lock: threading.Lock = threading.Lock()) -> T: @@ -122,16 +53,9 @@ def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Corout Blocks on *future* and returns the result as soon as it is resolved. The coroutine and all remaining tasks continue running in the background until complete. - - Note: This installs a :class:`chess.engine.EventLoopPolicy` for the entire - process. """ assert asyncio.iscoroutinefunction(coroutine) - with _policy_lock: - if not isinstance(asyncio.get_event_loop_policy(), EventLoopPolicy): - asyncio.set_event_loop_policy(EventLoopPolicy()) - future: concurrent.futures.Future[T] = concurrent.futures.Future() def background() -> None: diff --git a/docs/engine.rst b/docs/engine.rst index 02dd4548f..a326430e0 100644 --- a/docs/engine.rst +++ b/docs/engine.rst @@ -58,7 +58,6 @@ Example: Let Stockfish play against itself, 100 milliseconds per move. await engine.quit() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) .. autoclass:: chess.engine.Protocol @@ -126,7 +125,6 @@ Example: await engine.quit() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) .. autoclass:: chess.engine.Protocol @@ -189,7 +187,6 @@ Example: Stream information from the engine and stop on an arbitrary condition. await engine.quit() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) .. autoclass:: chess.engine.Protocol @@ -243,7 +240,6 @@ Options # [...] - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) .. autoclass:: chess.engine.Protocol @@ -315,5 +311,3 @@ Reference .. autoclass:: chess.engine.SimpleAnalysisResult :members: - -.. autofunction:: chess.engine.EventLoopPolicy diff --git a/examples/bratko_kopec/bratko_kopec.py b/examples/bratko_kopec/bratko_kopec.py index 62e3655a6..2553f4399 100755 --- a/examples/bratko_kopec/bratko_kopec.py +++ b/examples/bratko_kopec/bratko_kopec.py @@ -152,5 +152,4 @@ async def main() -> None: if __name__ == "__main__": - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) diff --git a/fuzz/engine.py b/fuzz/engine.py index a08d08bf3..ad0cb9fe9 100644 --- a/fuzz/engine.py +++ b/fuzz/engine.py @@ -7,7 +7,6 @@ logging.getLogger("chess.engine").setLevel(logging.CRITICAL) -asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) @PythonFuzz diff --git a/test.py b/test.py index 6419eb89f..73b96f71c 100755 --- a/test.py +++ b/test.py @@ -3114,7 +3114,6 @@ async def main(): await protocol.ping() mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_uci_debug(self): @@ -3130,7 +3129,6 @@ async def main(): protocol.debug(False) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_uci_go(self): @@ -3173,7 +3171,6 @@ async def main(): self.assertEqual(result.ponder, None) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_iota_log(self): @@ -3196,7 +3193,6 @@ async def main(): await protocol.play(board, chess.engine.Limit(time=5.0)) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_uci_analyse_mode(self): @@ -3243,7 +3239,6 @@ async def main(): self.assertEqual(best.ponder, chess.Move.from_uci("e7e5")) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_uci_play_after_analyse(self): @@ -3271,7 +3266,6 @@ async def main(): mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_uci_ponderhit(self): @@ -3387,7 +3381,6 @@ async def main(): mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_uci_info(self): @@ -3474,7 +3467,6 @@ async def main(): await protocol.send_game_result(checkmate_board) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_hiarcs_bestmove(self): @@ -3499,7 +3491,6 @@ async def main(): self.assertEqual(result.info["string"], "keep double space") mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_options(self): @@ -3562,7 +3553,6 @@ async def main(): await protocol.configure({"buttonvar": None}) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_replay(self): @@ -3624,7 +3614,6 @@ async def main(): self.assertEqual(result.move, board.parse_san("d4")) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_opponent(self): @@ -3682,7 +3671,6 @@ async def main(): result = await protocol.play(board, limit, game="bad game", opponent=bad_opponent) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_result(self): @@ -3772,7 +3760,6 @@ async def main(): await protocol.send_game_result(material_board) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_analyse(self): @@ -3810,7 +3797,6 @@ async def main(): self.assertEqual(info["pv"], [chess.Move.from_uci(move) for move in ["f7f6", "e2e4", "e7e6"]]) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_level(self): @@ -3855,7 +3841,6 @@ async def main(): self.assertEqual(result.move, chess.Move.from_uci("d2d4")) mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) def test_xboard_error(self): @@ -3874,7 +3859,6 @@ async def main(): mock.assert_done() - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) @catchAndSkip(FileNotFoundError, "need /bin/bash") @@ -3886,7 +3870,6 @@ async def main(): self.assertNotEqual(results[0], None) self.assertNotEqual(results[1], None) - asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy()) asyncio.run(main()) @catchAndSkip(FileNotFoundError, "need /bin/bash") From 61a660f5d94b5be60f5d488f04145cecdb27cf29 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:43:43 +0200 Subject: [PATCH 092/250] Rename acknowledgements section --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index cbacf299e..d8089b146 100644 --- a/README.rst +++ b/README.rst @@ -352,8 +352,8 @@ If you like, share interesting things you are using python-chess for, for exampl * an accessible chessboard that allows blind and visually impaired players to play chess against Stockfish – https://github.com/blindpandas/chessmart -Acknowledgements ----------------- +Prior art +--------- Thanks to the Stockfish authors and thanks to Sam Tannous for publishing his approach to `avoid rotated bitboards with direct lookup (PDF) `_ @@ -371,4 +371,4 @@ License ------- python-chess is licensed under the GPL 3 (or any later version at your option). -Check out LICENSE.txt for the full text. +Check out `LICENSE.txt` for the full text. From 773888594fe44c35b5d070a9b6b04464c07958ef Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:47:27 +0200 Subject: [PATCH 093/250] Fix outdated WDL model docs --- chess/engine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 6958479f9..4e18a3cf7 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -453,7 +453,8 @@ def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl: :param model: * ``sf``, the WDL model used by the latest Stockfish - (currently ``sf15.1``). + (currently ``sf16``). + * ``sf16``, the WDL model used by Stockfish 16. * ``sf15.1``, the WDL model used by Stockfish 15.1. * ``sf15``, the WDL model used by Stockfish 15. * ``sf14``, the WDL model used by Stockfish 14. From dc026b9b5a931faa6f47e79cb7da5c61a19bb53b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 20:57:31 +0200 Subject: [PATCH 094/250] Bump copyright year in docs --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index ede90b63b..22f960575 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,7 +34,7 @@ # General information about the project. project = "python-chess" -copyright = "2014–2022, Niklas Fiekas" +copyright = "2014–2023, Niklas Fiekas" # The version. version = chess.__version__ From 179b6f3032008a500f5c12ab760a7f4037b2b142 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 21:02:50 +0200 Subject: [PATCH 095/250] Remove experimental interactive PGN viewer (closes #753) --- chess/_interactive.py | 190 ------------------------------------------ chess/pgn.py | 5 -- 2 files changed, 195 deletions(-) delete mode 100644 chess/_interactive.py diff --git a/chess/_interactive.py b/chess/_interactive.py deleted file mode 100644 index edeef3df0..000000000 --- a/chess/_interactive.py +++ /dev/null @@ -1,190 +0,0 @@ -# TODO: Fix typing in this file. -# mypy: ignore-errors - -import chess.svg - - -class WidgetError(Exception): - """ - raised when ipywidgets is not installed - """ - - -class NotJupyter(Exception): - """ - raised when InteractiveViewer is instantiated from a non jupyter shell - """ - - -try: - from ipywidgets import Button, GridBox, Layout, HTML, Output, HBox, Select - from IPython.display import display, clear_output -except ModuleNotFoundError: - raise WidgetError("You need to have ipywidgets installed and running from Jupyter") - - -class InteractiveViewer: - def __new__(cls, game): - jupyter = True - try: - if get_ipython().__class__.__name__ != "ZMQInteractiveShell": - jupyter = False - except NameError: - jupyter = False - - if not jupyter: - raise NotJupyter("The interactive viewer only runs in Jupyter shell") - - return object.__new__(cls) - - def __init__(self, game): - self.game = game - self.__board = game.board() - self.__moves = list(game.mainline_moves()) - self.__white_moves = [str(move) for (i, move) in enumerate(self.__moves) if i % 2 == 0] - self.__black_moves = [str(move) for (i, move) in enumerate(self.__moves) if i % 2 == 1] - self.__move_list_len = len(self.__white_moves) - self.__num_moves = len(self.__moves) - self.__next_move = 0 if self.__moves else None - self.__out = Output() - - def __next_click(self, _): - move = self.__moves[self.__next_move] - self.__next_move += 1 - self.__board.push(move) - self.show() - - def __prev_click(self, _): - self.__board.pop() - self.__next_move -= 1 - self.show() - - def __reset_click(self, _): - self.__board.reset() - self.__next_move = 0 - self.show() - - def __white_select_change(self, change): - new = change["new"] - if (isinstance(new, dict)) and ("index" in new): - target = new["index"] * 2 - self.__seek(target) - self.show() - - def __black_select_change(self, change): - new = change["new"] - if (isinstance(new, dict)) and ("index" in new): - target = new["index"] * 2 + 1 - self.__seek(target) - self.show() - - def __seek(self, target): - while self.__next_move <= target: - move = self.__moves[self.__next_move] - self.__next_move += 1 - self.__board.push(move) - - while self.__next_move > target + 1: - self.__board.pop() - self.__next_move -= 1 - - def show(self): - display(self.__out) - next_move = Button( - icon="step-forward", - layout=Layout(width="60px", grid_area="right"), - disabled=self.__next_move >= self.__num_moves, - ) - - prev_move = Button( - icon="step-backward", - layout=Layout(width="60px", grid_area="left"), - disabled=self.__next_move == 0, - ) - - reset = Button( - icon="stop", - layout=Layout(width="60px", grid_area="middle"), - disabled=self.__next_move == 0, - ) - - if self.__next_move == 0: - white_move = None - black_move = None - else: - white_move = ( - self.__white_moves[self.__next_move // 2] - if (self.__next_move % 2) == 1 - else None - ) - black_move = ( - self.__black_moves[self.__next_move // 2 - 1] - if (self.__next_move % 2) == 0 - else None - ) - - white_move_list = Select( - options=self.__white_moves, - value=white_move, - rows=max(self.__move_list_len, 24), - disabled=False, - layout=Layout(width="80px"), - ) - - black_move_list = Select( - options=self.__black_moves, - value=black_move, - rows=max(self.__move_list_len, 24), - disabled=False, - layout=Layout(width="80px"), - ) - - white_move_list.observe(self.__white_select_change) - black_move_list.observe(self.__black_select_change) - - move_number_width = 3 + len(str(self.__move_list_len)) * 10 - - move_number = Select( - options=range(1, self.__move_list_len + 1), - value=None, - disabled=True, - rows=max(self.__move_list_len, 24), - layout=Layout(width=f"{move_number_width}px"), - ) - - move_list = HBox( - [move_number, white_move_list, black_move_list], - layout=Layout(height="407px", grid_area="moves"), - ) - - next_move.on_click(self.__next_click) - prev_move.on_click(self.__prev_click) - reset.on_click(self.__reset_click) - - with self.__out: - grid_box = GridBox( - children=[next_move, prev_move, reset, self.svg, move_list], - layout=Layout( - width=f"{390+move_number_width+160}px", - grid_template_rows="90% 10%", - grid_template_areas=""" - "top top top top top moves" - ". left middle right . moves" - """, - ), - ) - clear_output(wait=True) - display(grid_box) - - @property - def svg(self) -> HTML: - svg = chess.svg.board( - board=self.__board, - size=390, - lastmove=self.__board.peek() if self.__board.move_stack else None, - check=self.__board.king(self.__board.turn) - if self.__board.is_check() - else None, - ) - svg_widget = HTML(value=svg, layout=Layout(grid_area="top")) - return svg_widget diff --git a/chess/pgn.py b/chess/pgn.py index ae22afaf6..9ff218ead 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -804,11 +804,6 @@ def __init__(self, headers: Optional[Union[Mapping[str, str], Iterable[Tuple[str def board(self) -> chess.Board: return self.headers.board() - # TODO: Consider naming. - def _interactive_viewer(self) -> Any: - from chess._interactive import InteractiveViewer - return InteractiveViewer(self) # type: ignore - def ply(self) -> int: # Optimization: Parse FEN only for custom starting positions. return self.board().ply() if "FEN" in self.headers else 0 From bab76653b11e447f7431106025ddd4ebaefc407e Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 21:30:46 +0200 Subject: [PATCH 096/250] Let setup.py show better error on Python 3.7 --- setup.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index ed3d8b0bf..8c397e456 100755 --- a/setup.py +++ b/setup.py @@ -18,8 +18,13 @@ end of 2018. Consider upgrading to Python 3. """)) -if sys.version_info < (3, 7): - raise ImportError("Since version 1.0.0, python-chess requires Python 3.7 or later.") +if sys.version_info < (3, 8): + raise ImportError(textwrap.dedent("""\ + You are trying to install python-chess. + + Since version 1.11.0, python-chess requires Python 3.8 or later. + Since version 1.0.0, python-chess requires Python 3.7 or later. + """)) import chess From 86da00e86f458537bc1a0a6929149a9d2730dd9a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 27 Jul 2023 21:32:46 +0200 Subject: [PATCH 097/250] Fix rst syntax --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d8089b146..8ab138666 100644 --- a/README.rst +++ b/README.rst @@ -371,4 +371,4 @@ License ------- python-chess is licensed under the GPL 3 (or any later version at your option). -Check out `LICENSE.txt` for the full text. +Check out ``LICENSE.txt`` for the full text. From 60d38d5abea8ef1dc2a4787bd8a8981741324a78 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 30 Jul 2023 18:51:45 +0200 Subject: [PATCH 098/250] Start changelog for next release --- CHANGELOG.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a44b2b070..0fa76effa 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,15 @@ Changelog for python-chess ========================== +Upcoming in the next release +---------------------------- + +Changes: + +* Dropped support for Python 3.7, which had reached its end of life. +* `chess.engine.EventLoopPolicy` is no longer needed and now merely an alias + for the default event loop policy. + New in v1.10.0 (27th Jul 2023) ------------------------------ From 7857668ed939d346200ac624bcb7e6cecbebf19e Mon Sep 17 00:00:00 2001 From: mauricesvp Date: Wed, 2 Aug 2023 16:00:19 +0200 Subject: [PATCH 099/250] Add PGN TimeControl Header Parser --- chess/pgn.py | 100 ++++++++++++++++++++++++ data/pgn/nepomniachtchi-liren-game1.pgn | 22 ++++++ test.py | 47 +++++++++++ 3 files changed, 169 insertions(+) create mode 100644 data/pgn/nepomniachtchi-liren-game1.pgn diff --git a/chess/pgn.py b/chess/pgn.py index 9ff218ead..72c613dd4 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1,6 +1,7 @@ from __future__ import annotations import abc +import dataclasses import enum import itertools import logging @@ -141,6 +142,39 @@ class SkipType(enum.Enum): ResultT = TypeVar("ResultT", covariant=True) +class TimeControlType(enum.Enum): + UNKNOW = 0 + UNLIMITED = 1 + STANDARD = 2 + RAPID = 3 + BLITZ = 4 + BULLET = 5 + + +@dataclasses.dataclass +class TimeControlPart: + moves: int = 0 + time: int = 0 + increment: float = 0 + delay: float = 0 + + +@dataclasses.dataclass +class TimeControl: + """ + PGN TimeControl Parser + Spec: http://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm#c9.6 + + Not Yet Implemented: + - Hourglass/Sandclock ('*' prefix) + - Differentiating between Bronstein and Simple Delay (Not part of the PGN Spec) + - More Info: https://en.wikipedia.org/wiki/Chess_clock#Timing_methods + """ + + parts: list[TimeControlPart] = dataclasses.field(default_factory=list) + type: TimeControlType = TimeControlType.UNKNOW + + class _AcceptFrame: def __init__(self, node: ChildNode, *, is_variation: bool = False, sidelines: bool = True): self.state = "pre" @@ -859,6 +893,14 @@ def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: visitor.end_game() return visitor.result() + def time_control(self) -> TimeControl: + """ + Returns the time control of the game. If the game has no time control + information, the default time control ('UNKNOWN') is returned. + """ + time_control_header = self.headers.get("TimeControl", "") + return parse_time_control(time_control_header) + @classmethod def from_board(cls: Type[GameT], board: chess.Board) -> GameT: """Creates a game from the move stack of a :class:`~chess.Board()`.""" @@ -1763,3 +1805,61 @@ def skip_game(handle: TextIO) -> bool: Skips a game. Returns ``True`` if a game was found and skipped. """ return bool(read_game(handle, Visitor=SkipVisitor)) + + +def parse_time_control(time_control: str) -> TimeControl: + tc = TimeControl() + + if not time_control: + return tc + + if time_control.startswith("?"): + return tc + + if time_control.startswith("-"): + tc.type = TimeControlType.UNLIMITED + return tc + + def _parse_part(part: str) -> TimeControlPart: + tcp = TimeControlPart() + + moves_time, *bonus = part.split("+") + + if bonus: + bonus = bonus[0] + if bonus.lower().endswith("d"): + tcp.delay = float(bonus[:-1]) + else: + tcp.increment = float(bonus) + + moves, *time = moves_time.split("/") + if time: + tcp.moves = int(moves) + tcp.time = int(time[0]) + else: + tcp.moves = 0 + tcp.time = int(moves) + + return tcp + + tc.parts = [_parse_part(part) for part in time_control.split(":")] + + if len(tc.parts) > 1: + for part in tc.parts[:-1]: + if part.moves == 0: + raise ValueError("Only last part can be 'sudden death'.") + + # Classification according to https://www.fide.com/FIDE/handbook/LawsOfChess.pdf + # (Bullet added) + base_time = tc.parts[0].time + increment = tc.parts[0].increment + if (base_time + 60 * increment) < 3 * 60: + tc.type = TimeControlType.BULLET + elif (base_time + 60 * increment) < 15 * 60: + tc.type = TimeControlType.BLITZ + elif (base_time + 60 * increment) < 60 * 60: + tc.type = TimeControlType.RAPID + else: + tc.type = TimeControlType.STANDARD + + return tc diff --git a/data/pgn/nepomniachtchi-liren-game1.pgn b/data/pgn/nepomniachtchi-liren-game1.pgn new file mode 100644 index 000000000..ea3234154 --- /dev/null +++ b/data/pgn/nepomniachtchi-liren-game1.pgn @@ -0,0 +1,22 @@ +[Event "FIDE World Championship 2023"] +[Site "Astana KAZ"] +[Date "2023.04.09"] +[Round "1"] +[White "Nepomniachtchi, Ian"] +[Black "Liren, Ding"] +[Result "1/2-1/2"] +[TimeControl "40/7200:20/3600:900+30"] +[WhiteFideId "4168119"] +[BlackFideId "8603677"] +[WhiteElo "2795"] +[BlackElo "2788"] + +1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Bxc6 dxc6 +7. Re1 Nd7 8. d4 exd4 9. Qxd4 O-O 10. Bf4 Nc5 11. Qe3 Bg4 12. Nd4 +Qd7 13. Nc3 Rad8 14. Nf5 Ne6 15. Nxe7+ Qxe7 16. Bg3 Bh5 17. f3 f6 +18. h3 h6 19. Kh2 Bf7 20. Rad1 b6 21. a3 a5 22. Ne2 Rxd1 23. Rxd1 +Rd8 24. Rd3 c5 25. Qd2 c6 26. Rxd8+ Nxd8 27. Qf4 b5 28. Qb8 Kh7 +29. Bd6 Qd7 30. Ng3 Ne6 31. f4 h5 32. c3 c4 33. h4 Qd8 34. Qb7 +Be8 35. Nf5 Qd7 36. Qb8 Qd8 37. Qxd8 Nxd8 38. Nd4 Nb7 39. e5 Kg8 +40. Kg3 Bd7 41. Bc7 Nc5 42. Bxa5 Kf7 43. Bb4 Nd3 44. e6+ Bxe6 +45. Nxc6 Bd7 46. Nd4 Nxb2 47. Kf3 Nd3 48. g3 Nc1 49. Ke3 1/2-1/2 diff --git a/test.py b/test.py index 73b96f71c..e1d0d50c5 100755 --- a/test.py +++ b/test.py @@ -2493,6 +2493,53 @@ def test_read_headers(self): self.assertEqual(first_drawn_game.headers["Site"], "03") self.assertEqual(first_drawn_game[0].move, chess.Move.from_uci("d2d3")) + def test_parse_time_control(self): + with open("data/pgn/nepomniachtchi-liren-game1.pgn") as pgn: + game = chess.pgn.read_game(pgn) + tc = game.time_control() + + self.assertEqual(tc, chess.pgn.parse_time_control(game.headers["TimeControl"])) + + self.assertEqual(tc.type, chess.pgn.TimeControlType.STANDARD) + self.assertEqual(len(tc.parts), 3) + + tcp1, tcp2, tcp3 = tc.parts + + self.assertEqual(tcp1, chess.pgn.TimeControlPart(40, 7200)) + self.assertEqual(tcp2, chess.pgn.TimeControlPart(20, 3600)) + self.assertEqual(tcp3, chess.pgn.TimeControlPart(0, 900, 30)) + + self.assertEqual(chess.pgn.TimeControlType.BULLET, chess.pgn.parse_time_control("60").type) + self.assertEqual(chess.pgn.TimeControlType.BULLET, chess.pgn.parse_time_control("60+1").type) + + self.assertEqual(chess.pgn.TimeControlType.BLITZ, chess.pgn.parse_time_control("60+2").type) + self.assertEqual(chess.pgn.TimeControlType.BLITZ, chess.pgn.parse_time_control("300").type) + self.assertEqual(chess.pgn.TimeControlType.BLITZ, chess.pgn.parse_time_control("300+3").type) + + self.assertEqual(chess.pgn.TimeControlType.RAPID, chess.pgn.parse_time_control("300+10").type) + self.assertEqual(chess.pgn.TimeControlType.RAPID, chess.pgn.parse_time_control("1800").type) + self.assertEqual(chess.pgn.TimeControlType.RAPID, chess.pgn.parse_time_control("1800+10").type) + + self.assertEqual(chess.pgn.TimeControlType.STANDARD, chess.pgn.parse_time_control("1800+30").type) + self.assertEqual(chess.pgn.TimeControlType.STANDARD, chess.pgn.parse_time_control("5400").type) + self.assertEqual(chess.pgn.TimeControlType.STANDARD, chess.pgn.parse_time_control("5400+30").type) + + with self.assertRaises(ValueError): + chess.pgn.parse_time_control("300+a") + + with self.assertRaises(ValueError): + chess.pgn.parse_time_control("300+ad") + + with self.assertRaises(ValueError): + chess.pgn.parse_time_control("600:20/180") + + with self.assertRaises(ValueError): + chess.pgn.parse_time_control("abc") + + with self.assertRaises(ValueError): + chess.pgn.parse_time_control("40/abc") + + def test_visit_board(self): class TraceVisitor(chess.pgn.BaseVisitor): def __init__(self): From acc85c2c4ede81ccd79183cb05c2754663bcc658 Mon Sep 17 00:00:00 2001 From: mauricesvp Date: Wed, 2 Aug 2023 20:53:52 +0200 Subject: [PATCH 100/250] Fix mypy --- chess/pgn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 72c613dd4..55eddbc29 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1826,11 +1826,11 @@ def _parse_part(part: str) -> TimeControlPart: moves_time, *bonus = part.split("+") if bonus: - bonus = bonus[0] - if bonus.lower().endswith("d"): - tcp.delay = float(bonus[:-1]) + _bonus = bonus[0] + if _bonus.lower().endswith("d"): + tcp.delay = float(_bonus[:-1]) else: - tcp.increment = float(bonus) + tcp.increment = float(_bonus) moves, *time = moves_time.split("/") if time: From 48bd065b14c5b61cc94227ed5532a97db8ac5a45 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 2 Aug 2023 21:25:18 +0200 Subject: [PATCH 101/250] Add ColorName literal type --- chess/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chess/__init__.py b/chess/__init__.py index 0604cec54..65719fd5c 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -29,7 +29,8 @@ Color = bool COLORS = [WHITE, BLACK] = [True, False] -COLOR_NAMES = ["black", "white"] +ColorName = Literal["white", "black"] +COLOR_NAMES: List[ColorName] = ["black", "white"] PieceType = int PIECE_TYPES = [PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING] = range(1, 7) From 552d6b8060a4960c765eb591c37a1252f857adbc Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 2 Aug 2023 21:48:32 +0200 Subject: [PATCH 102/250] Import TypedDict directly --- chess/engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 4e18a3cf7..ed01e353a 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -24,7 +24,7 @@ from chess import Color from types import TracebackType -from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypeVar, Union +from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypedDict, TypeVar, Union WdlModel = Literal["sf", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] @@ -217,7 +217,7 @@ def __repr__(self) -> str: if getattr(self, attr) is not None)) -class InfoDict(typing.TypedDict, total=False): +class InfoDict(TypedDict, total=False): """ Dictionary of aggregated information sent by the engine. From e1732436dcd590ea02cd51810c05d9e0ea030cab Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 2 Aug 2023 22:50:44 +0200 Subject: [PATCH 103/250] Remove _policy_lock --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index ed01e353a..fcd92563d 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -46,7 +46,7 @@ EventLoopPolicy = asyncio.DefaultEventLoopPolicy -def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: bool = False, _policy_lock: threading.Lock = threading.Lock()) -> T: +def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: bool = False) -> T: """ Runs ``coroutine(future)`` in a new event loop on a background thread. From 90eeeb0f9047197bcdfb26879061545cc34bbc94 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 2 Aug 2023 22:53:43 +0200 Subject: [PATCH 104/250] Fix unused debug in chess.engine.run_in_background() --- chess/engine.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index fcd92563d..5f50a1414 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -46,7 +46,7 @@ EventLoopPolicy = asyncio.DefaultEventLoopPolicy -def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: bool = False) -> T: +def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: Optional[bool] = None) -> T: """ Runs ``coroutine(future)`` in a new event loop on a background thread. @@ -60,7 +60,7 @@ def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Corout def background() -> None: try: - asyncio.run(coroutine(future)) + asyncio.run(coroutine(future), debug=debug) future.cancel() except Exception as exc: future.set_exception(exc) @@ -2894,7 +2894,7 @@ def _shutdown() -> None: self.protocol.loop.call_soon_threadsafe(_shutdown) @classmethod - def popen(cls, Protocol: Type[Protocol], command: Union[str, List[str]], *, timeout: Optional[float] = 10.0, debug: bool = False, setpgrp: bool = False, **popen_args: Any) -> SimpleEngine: + def popen(cls, Protocol: Type[Protocol], command: Union[str, List[str]], *, timeout: Optional[float] = 10.0, debug: Optional[bool] = None, setpgrp: bool = False, **popen_args: Any) -> SimpleEngine: async def background(future: concurrent.futures.Future[SimpleEngine]) -> None: transport, protocol = await Protocol.popen(command, setpgrp=setpgrp, **popen_args) threading.current_thread().name = f"{cls.__name__} (pid={transport.get_pid()})" @@ -2911,7 +2911,7 @@ async def background(future: concurrent.futures.Future[SimpleEngine]) -> None: return run_in_background(background, name=f"{cls.__name__} (command={command!r})", debug=debug) @classmethod - def popen_uci(cls, command: Union[str, List[str]], *, timeout: Optional[float] = 10.0, debug: bool = False, setpgrp: bool = False, **popen_args: Any) -> SimpleEngine: + def popen_uci(cls, command: Union[str, List[str]], *, timeout: Optional[float] = 10.0, debug: Optional[bool] = None, setpgrp: bool = False, **popen_args: Any) -> SimpleEngine: """ Spawns and initializes a UCI engine. Returns a :class:`~chess.engine.SimpleEngine` instance. @@ -2919,7 +2919,7 @@ def popen_uci(cls, command: Union[str, List[str]], *, timeout: Optional[float] = return cls.popen(UciProtocol, command, timeout=timeout, debug=debug, setpgrp=setpgrp, **popen_args) @classmethod - def popen_xboard(cls, command: Union[str, List[str]], *, timeout: Optional[float] = 10.0, debug: bool = False, setpgrp: bool = False, **popen_args: Any) -> SimpleEngine: + def popen_xboard(cls, command: Union[str, List[str]], *, timeout: Optional[float] = 10.0, debug: Optional[bool] = None, setpgrp: bool = False, **popen_args: Any) -> SimpleEngine: """ Spawns and initializes an XBoard engine. Returns a :class:`~chess.engine.SimpleEngine` instance. From 35b961c17b7a6dcbad98f4f3bfb9df115a28db29 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 6 Aug 2023 10:47:25 +0200 Subject: [PATCH 105/250] Avoid start_new_session if possible --- chess/engine.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 5f50a1414..01ee08b3e 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1180,7 +1180,11 @@ async def popen(cls: Type[ProtocolT], command: Union[str, List[str]], *, setpgrp popen_args["creationflags"] = popen_args.get("creationflags", 0) | subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore except AttributeError: # Unix. - popen_args["start_new_session"] = True + if sys.version_info >= (3, 11): + popen_args["process_group"] = 0 + else: + # Before Python 3.11 + popen_args["start_new_session"] = True return await asyncio.get_running_loop().subprocess_exec(cls, *command, **popen_args) From b6a04e8db55b6fca08250ba883aba50c60a3c589 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 3 Sep 2023 21:37:44 -0700 Subject: [PATCH 106/250] Delete unused imports --- chess/engine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 01ee08b3e..0b0f061dc 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -10,14 +10,12 @@ import enum import logging import math -import warnings import shlex import subprocess import sys import threading import time import typing -import os import re import chess From e9997d52c8c06b773a797029ee7ba8630c0829bd Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 5 Sep 2023 22:56:14 -0700 Subject: [PATCH 107/250] Create new function for parsing engine output The function next_token() extracts the next word from a string and removes the leading and trailing whitespace around that word. It also returns the remainder of the string unchanged. Using this function instead of split() gets rid of extraneous whitespace when searching for keywords and preserves whitespace in strings generated by users and their engines. --- chess/engine.py | 169 +++++++++++++++++++++++++++++++----------------- 1 file changed, 110 insertions(+), 59 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 0b0f061dc..22b6125dd 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1303,14 +1303,15 @@ def start(self, engine: UciProtocol) -> None: engine.send_line("uci") def line_received(self, engine: UciProtocol, line: str) -> None: - if line == "uciok" and not self.result.done(): + token, remaining = _next_token(line) + if line.strip() == "uciok" and not self.result.done(): engine.initialized = True self.result.set_result(None) self.set_finished() - elif line.startswith("option "): - self._option(engine, line.split(" ", 1)[1]) - elif line.startswith("id "): - self._id(engine, line.split(" ", 1)[1]) + elif token == "option": + self._option(engine, remaining) + elif token == "id": + self._id(engine, remaining) def _option(self, engine: UciProtocol, arg: str) -> None: current_parameter = None @@ -1371,8 +1372,8 @@ def _option(self, engine: UciProtocol, arg: str) -> None: engine.target_config[option.name] = option.default def _id(self, engine: UciProtocol, arg: str) -> None: - key, value = arg.split(" ", 1) - engine.id[key] = value + key, value = _next_token(arg) + engine.id[key] = value.strip() return await self.communicate(UciInitializeCommand) @@ -1587,11 +1588,12 @@ def start(self, engine: UciProtocol) -> None: self._readyok(engine) def line_received(self, engine: UciProtocol, line: str) -> None: - if line.startswith("info "): - self._info(engine, line.split(" ", 1)[1]) - elif line.startswith("bestmove "): - self._bestmove(engine, line.split(" ", 1)[1]) - elif line == "readyok" and self.sent_isready: + token, remaining = _next_token(line) + if token == "info": + self._info(engine, remaining) + elif token == "bestmove": + self._bestmove(engine, remaining) + elif line.strip() == "readyok" and self.sent_isready: self._readyok(engine) else: LOGGER.warning("%s: Unexpected engine output: %r", engine, line) @@ -1679,11 +1681,12 @@ def start(self, engine: UciProtocol) -> None: self._readyok(engine) def line_received(self, engine: UciProtocol, line: str) -> None: - if line.startswith("info "): - self._info(engine, line.split(" ", 1)[1]) - elif line.startswith("bestmove "): - self._bestmove(engine, line.split(" ", 1)[1]) - elif line == "readyok" and self.sent_isready: + token, remaining = _next_token(line) + if token == "info": + self._info(engine, remaining) + elif token == "bestmove": + self._bestmove(engine, remaining) + elif line.strip() == "readyok" and self.sent_isready: self._readyok(engine) else: LOGGER.warning("%s: Unexpected engine output: %r", engine, line) @@ -1733,34 +1736,39 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL if not selector: return info - tokens = arg.split(" ") - while tokens: - parameter = tokens.pop(0) + remaining_line = arg + while remaining_line: + parameter, remaining_line = _next_token(remaining_line) if parameter == "string": - info["string"] = " ".join(tokens) + info["string"] = remaining_line break elif parameter in ["depth", "seldepth", "nodes", "multipv", "currmovenumber", "hashfull", "nps", "tbhits", "cpuload"]: try: - info[parameter] = int(tokens.pop(0)) # type: ignore + number, remaining_line = _next_token(remaining_line) + info[parameter] = int(number) # type: ignore except (ValueError, IndexError): LOGGER.error("Exception parsing %s from info: %r", parameter, arg) elif parameter == "time": try: - info["time"] = int(tokens.pop(0)) / 1000.0 + time_ms, remaining_line = _next_token(remaining_line) + info["time"] = int(time_ms) / 1000.0 except (ValueError, IndexError): LOGGER.error("Exception parsing %s from info: %r", parameter, arg) elif parameter == "ebf": try: - info["ebf"] = float(tokens.pop(0)) + number, remaining_line = _next_token(remaining_line) + info["ebf"] = float(number) except (ValueError, IndexError): LOGGER.error("Exception parsing %s from info: %r", parameter, arg) elif parameter == "score" and selector & INFO_SCORE: try: - kind = tokens.pop(0) - value = tokens.pop(0) - if tokens and tokens[0] in ["lowerbound", "upperbound"]: - info[tokens.pop(0)] = True # type: ignore + kind, remaining_line = _next_token(remaining_line) + value, remaining_line = _next_token(remaining_line) + token, remaining_after_token = _next_token(remaining_line) + if token in ["lowerbound", "upperbound"]: + info[token] = True # type: ignore + remaining_line = remaining_after_token if kind == "cp": info["score"] = PovScore(Cp(int(value)), root_board.turn) elif kind == "mate": @@ -1771,7 +1779,8 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL LOGGER.error("Exception parsing score from info: %r", arg) elif parameter == "currmove": try: - info["currmove"] = chess.Move.from_uci(tokens.pop(0)) + current_move, remaining_line = _next_token(remaining_line) + info["currmove"] = chess.Move.from_uci(current_move) except (ValueError, IndexError): LOGGER.error("Exception parsing currmove from info: %r", arg) elif parameter == "currline" and selector & INFO_CURRLINE: @@ -1779,13 +1788,19 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL if "currline" not in info: info["currline"] = {} - cpunr = int(tokens.pop(0)) + cpunr_text, remaining_line = _next_token(remaining_line) + cpunr = int(cpunr_text) currline: List[chess.Move] = [] info["currline"][cpunr] = currline board = root_board.copy(stack=False) - while tokens and UCI_REGEX.match(tokens[0]): - currline.append(board.push_uci(tokens.pop(0))) + while True: + next_move, remaining_line_after_move = _next_token(remaining_line) + if UCI_REGEX.match(next_move): + currline.append(board.push_uci(next_move)) + remaining_line = remaining_line_after_move + else: + break except (ValueError, IndexError): LOGGER.error("Exception parsing currline from info: %r, position at root: %s", arg, root_board.fen()) elif parameter == "refutation" and selector & INFO_REFUTATION: @@ -1794,13 +1809,19 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL info["refutation"] = {} board = root_board.copy(stack=False) - refuted = board.push_uci(tokens.pop(0)) + refuted_text, remaining_line = _next_token(remaining_line) + refuted = board.push_uci(refuted_text) refuted_by: List[chess.Move] = [] info["refutation"][refuted] = refuted_by - while tokens and UCI_REGEX.match(tokens[0]): - refuted_by.append(board.push_uci(tokens.pop(0))) + while True: + token, remaining_line_after_move = _next_token(remaining_line) + if UCI_REGEX.match(token): + refuted_by.append(board.push_uci(token)) + remaining_line = remaining_line_after_move + else: + break except (ValueError, IndexError): LOGGER.error("Exception parsing refutation from info: %r, position at root: %s", arg, root_board.fen()) elif parameter == "pv" and selector & INFO_PV: @@ -1808,13 +1829,21 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL pv: List[chess.Move] = [] info["pv"] = pv board = root_board.copy(stack=False) - while tokens and UCI_REGEX.match(tokens[0]): - pv.append(board.push_uci(tokens.pop(0))) + while True: + token, remaining_line_after_pv = _next_token(remaining_line) + if UCI_REGEX.match(token): + pv.append(board.push_uci(token)) + remaining_line = remaining_line_after_pv + else: + break except (ValueError, IndexError): LOGGER.error("Exception parsing pv from info: %r, position at root: %s", arg, root_board.fen()) elif parameter == "wdl": try: - info["wdl"] = PovWdl(Wdl(int(tokens.pop(0)), int(tokens.pop(0)), int(tokens.pop(0))), root_board.turn) + wins, remaining_line = _next_token(remaining_line) + draws, remaining_line = _next_token(remaining_line) + losses, remaining_line = _next_token(remaining_line) + info["wdl"] = PovWdl(Wdl(int(wins), int(draws), int(losses)), root_board.turn) except (ValueError, IndexError): LOGGER.error("Exception parsing wdl from info: %r", arg) @@ -1944,10 +1973,11 @@ def timeout(self, engine: XBoardProtocol) -> None: self.end(engine) def line_received(self, engine: XBoardProtocol, line: str) -> None: - if line.startswith("#"): + token, remaining = _next_token(line) + if token.startswith("#"): pass - elif line.startswith("feature "): - self._feature(engine, line.split(" ", 1)[1]) + elif token == "feature": + self._feature(engine, remaining) elif XBOARD_ERROR_REGEX.match(line): raise EngineError(line) @@ -2159,32 +2189,35 @@ def start(self, engine: XBoardProtocol) -> None: engine.send_line("go") def line_received(self, engine: XBoardProtocol, line: str) -> None: - if line.startswith("move "): - self._move(engine, line.split(" ", 1)[1]) - elif line.startswith("Hint: "): - self._hint(engine, line.split(" ", 1)[1]) - elif line == self.pong_after_move: - if not self.result.done(): - self.result.set_result(self.play_result) - if not ponder: + token, remaining = _next_token(line) + if token == "move": + self._move(engine, remaining.strip()) + elif token == "Hint:": + self._hint(engine, remaining.strip()) + elif token == "pong": + pong_line = f"{token} {remaining.strip()}" + if pong_line == self.pong_after_move: + if not self.result.done(): + self.result.set_result(self.play_result) + if not ponder: + self.set_finished() + elif pong_line == self.pong_after_ponder: + if not self.result.done(): + self.result.set_result(self.play_result) self.set_finished() - elif line == self.pong_after_ponder: - if not self.result.done(): - self.result.set_result(self.play_result) - self.set_finished() - elif line == "offer draw": + elif f"{token} {remaining.strip()}" == "offer draw": if not self.result.done(): self.play_result.draw_offered = True self._ping_after_move(engine) - elif line == "resign": + elif line.strip() == "resign": if not self.result.done(): self.play_result.resigned = True self._ping_after_move(engine) - elif line.startswith("1-0") or line.startswith("0-1") or line.startswith("1/2-1/2"): + elif token in ["1-0", "0-1", "1/2-1/2"]: if "resign" in line and not self.result.done(): self.play_result.resigned = True self._ping_after_move(engine) - elif line.startswith("#"): + elif token.startswith("#"): pass elif XBOARD_ERROR_REGEX.match(line): engine.first_game = True # Board state might no longer be in sync @@ -2291,11 +2324,12 @@ def start(self, engine: XBoardProtocol) -> None: self.time_limit_handle = None def line_received(self, engine: XBoardProtocol, line: str) -> None: - if line.startswith("#"): + token, remaining = _next_token(line) + if token.startswith("#"): pass elif len(line.split()) >= 4 and line.lstrip()[0].isdigit(): self._post(engine, line) - elif line == self.final_pong: + elif f"{token} {remaining.strip()}" == self.final_pong: self.end(engine) elif XBOARD_ERROR_REGEX.match(line): engine.first_game = True # Board state might no longer be in sync @@ -2551,6 +2585,23 @@ def _parse_xboard_post(line: str, root_board: chess.Board, selector: Info = INFO return info +def _next_token(line: str) -> tuple[str, str]: + """Get the next token in a whitespace-delimited line of text. + + The result is returned as a 2-part tuple of strings. + + If the input line is empty or all whitespace, then the result is two + empty strings. + + If the input line is not empty and not completely whitespace, then + the first element of the returned tuple is a single word with + leading and trailing whitespace removed. The second element is the + unchanged rest of the line.""" + + parts = line.split(maxsplit=1) + return (parts[0] if parts else "", parts[1] if len(parts) == 2 else "") + + class BestMove: """Returned by :func:`chess.engine.AnalysisResult.wait()`.""" From a68636e7a82841e4389b1d53390b6b33ff7a43e5 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 01:34:03 -0700 Subject: [PATCH 108/250] Split on all whitespace --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 22b6125dd..c8ed5cd4d 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1324,7 +1324,7 @@ def _option(self, engine: UciProtocol, arg: str) -> None: current_var = None var = [] - for token in arg.strip().split(" "): + for token in arg.split(): if token == "name" and not name: current_parameter = "name" elif token == "type" and not type: From dbc278f7cedb33409fc60186df20e1ac55ab39b3 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 01:34:40 -0700 Subject: [PATCH 109/250] Gather repeated code in option parsing --- chess/engine.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c8ed5cd4d..1ec7c2c8e 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1323,6 +1323,13 @@ def _option(self, engine: UciProtocol, arg: str) -> None: max = None current_var = None var = [] + + def parse_min_max_value(token: str, which: Literal["min", "max"]): + try: + return int(token) + except ValueError: + LOGGER.exception(f"Exception parsing option {which}") + return None for token in arg.split(): if token == "name" and not name: @@ -1349,15 +1356,9 @@ def _option(self, engine: UciProtocol, arg: str) -> None: elif current_parameter == "var": current_var.append(token) elif current_parameter == "min": - try: - min = int(token) - except ValueError: - LOGGER.exception("Exception parsing option min") + min = parse_min_max_value(token, "min") elif current_parameter == "max": - try: - max = int(token) - except ValueError: - LOGGER.exception("Exception parsing option max") + max = parse_min_max_value(token, "max") if current_var is not None: var.append(" ".join(current_var)) From 2e6ff83ace87d54da0cea6c679ae1b642afe8331 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 02:09:09 -0700 Subject: [PATCH 110/250] Create function for repeated code --- chess/engine.py | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 1ec7c2c8e..72681a627 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1732,6 +1732,18 @@ async def quit(self) -> None: UCI_REGEX = re.compile(r"^[a-h][1-8][a-h][1-8][pnbrqk]?|[PNBRQK]@[a-h][1-8]|0000\Z") +def _create_variation_line(root_board: chess.Board, line: str) -> tuple[list[chess.Move], str]: + board = root_board.copy(stack=False) + currline: list[chess.Move] = [] + while True: + next_move, remaining_line_after_move = _next_token(line) + if UCI_REGEX.match(next_move): + currline.append(board.push_uci(next_move)) + line = remaining_line_after_move + else: + return currline, line + + def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL) -> InfoDict: info: InfoDict = {} if not selector: @@ -1791,17 +1803,8 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL cpunr_text, remaining_line = _next_token(remaining_line) cpunr = int(cpunr_text) - currline: List[chess.Move] = [] + currline, remaining_line = _create_variation_line(root_board, remaining_line) info["currline"][cpunr] = currline - - board = root_board.copy(stack=False) - while True: - next_move, remaining_line_after_move = _next_token(remaining_line) - if UCI_REGEX.match(next_move): - currline.append(board.push_uci(next_move)) - remaining_line = remaining_line_after_move - else: - break except (ValueError, IndexError): LOGGER.error("Exception parsing currline from info: %r, position at root: %s", arg, root_board.fen()) elif parameter == "refutation" and selector & INFO_REFUTATION: @@ -1813,30 +1816,14 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL refuted_text, remaining_line = _next_token(remaining_line) refuted = board.push_uci(refuted_text) - refuted_by: List[chess.Move] = [] + refuted_by, remaining_line = _create_variation_line(board, remaining_line) info["refutation"][refuted] = refuted_by - - while True: - token, remaining_line_after_move = _next_token(remaining_line) - if UCI_REGEX.match(token): - refuted_by.append(board.push_uci(token)) - remaining_line = remaining_line_after_move - else: - break except (ValueError, IndexError): LOGGER.error("Exception parsing refutation from info: %r, position at root: %s", arg, root_board.fen()) elif parameter == "pv" and selector & INFO_PV: try: - pv: List[chess.Move] = [] + pv, remaining_line = _create_variation_line(root_board, remaining_line) info["pv"] = pv - board = root_board.copy(stack=False) - while True: - token, remaining_line_after_pv = _next_token(remaining_line) - if UCI_REGEX.match(token): - pv.append(board.push_uci(token)) - remaining_line = remaining_line_after_pv - else: - break except (ValueError, IndexError): LOGGER.error("Exception parsing pv from info: %r, position at root: %s", arg, root_board.fen()) elif parameter == "wdl": From 7aaf9d324f28e9b6a3abc82e284b7e5224b8438f Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 02:20:11 -0700 Subject: [PATCH 111/250] Fix tox.ini comments Latest version of flake8 no longer allows inline comments in config file. --- tox.ini | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index 665e9f38b..f629723cd 100644 --- a/tox.ini +++ b/tox.ini @@ -20,11 +20,18 @@ commands = [flake8] ignore = - E126 E131 # Allow over-indent and unaligned indent - E241 # Allow indenting array elements - E302 E305 # Allow grouping functions - E741 # Allow "ambiguous" variable names - W504 # Allow binary operators before EOL (end of line) - E704 E301 # Allow "def overloaded(): ..." - E722 # Bare except (with or without reraise) + # Allow over-indent and unaligned indent + E126 E131 + # Allow indenting array elements + E241 + # Allow grouping functions + E302 E305 + # Allow "ambiguous" variable names + E741 + # Allow binary operators before EOL (end of line) + W504 + # Allow "def overloaded(): ..." + E704 E301 + # Bare except (with or without reraise) + E722 max-line-length = 160 From 3cb886c7a0bae1c1163db6340da8c989d4625a66 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 02:22:53 -0700 Subject: [PATCH 112/250] Add return value annotation --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 72681a627..74aeb9980 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1324,7 +1324,7 @@ def _option(self, engine: UciProtocol, arg: str) -> None: current_var = None var = [] - def parse_min_max_value(token: str, which: Literal["min", "max"]): + def parse_min_max_value(token: str, which: Literal["min", "max"]) -> Optional[int]: try: return int(token) except ValueError: From 69041525dd05b496ab01d839880f437093f66536 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 16:22:58 -0700 Subject: [PATCH 113/250] Delete trailing whitespace --- chess/engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 74aeb9980..7a8bbc845 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1323,7 +1323,7 @@ def _option(self, engine: UciProtocol, arg: str) -> None: max = None current_var = None var = [] - + def parse_min_max_value(token: str, which: Literal["min", "max"]) -> Optional[int]: try: return int(token) @@ -1742,7 +1742,7 @@ def _create_variation_line(root_board: chess.Board, line: str) -> tuple[list[che line = remaining_line_after_move else: return currline, line - + def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL) -> InfoDict: info: InfoDict = {} From 55060d497b2c56d96ff5935329645c5d2f3dc818 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 10 Sep 2023 16:24:24 -0700 Subject: [PATCH 114/250] Simplify UCI option parsing with regex --- chess/engine.py | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 7a8bbc845..80312fa19 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1274,6 +1274,8 @@ def __repr__(self) -> str: return "<{} at {:#x} (state={}, result={}, finished={}>".format(type(self).__name__, id(self), self.state, self.result, self.finished) +UCI_OPTION_REGEX = re.compile(r"\s*(name|type|default|min|max|var)\s*") + class UciProtocol(Protocol): """ An implementation of the @@ -1314,14 +1316,11 @@ def line_received(self, engine: UciProtocol, line: str) -> None: self._id(engine, remaining) def _option(self, engine: UciProtocol, arg: str) -> None: - current_parameter = None - - name: List[str] = [] - type: List[str] = [] - default: List[str] = [] + name = "" + type = "" + default = "" min = None max = None - current_var = None var = [] def parse_min_max_value(token: str, which: Literal["min", "max"]) -> Optional[int]: @@ -1331,7 +1330,8 @@ def parse_min_max_value(token: str, which: Literal["min", "max"]) -> Optional[in LOGGER.exception(f"Exception parsing option {which}") return None - for token in arg.split(): + current_parameter = None + for token in UCI_OPTION_REGEX.split(arg): if token == "name" and not name: current_parameter = "name" elif token == "type" and not type: @@ -1344,27 +1344,21 @@ def parse_min_max_value(token: str, which: Literal["min", "max"]) -> Optional[in current_parameter = "max" elif token == "var": current_parameter = "var" - if current_var is not None: - var.append(" ".join(current_var)) - current_var = [] elif current_parameter == "name": - name.append(token) + name = token elif current_parameter == "type": - type.append(token) + type = token elif current_parameter == "default": - default.append(token) + default = token elif current_parameter == "var": - current_var.append(token) + var.append(token) elif current_parameter == "min": min = parse_min_max_value(token, "min") elif current_parameter == "max": max = parse_min_max_value(token, "max") - if current_var is not None: - var.append(" ".join(current_var)) - - without_default = Option(" ".join(name), " ".join(type), None, min, max, var) - option = Option(without_default.name, without_default.type, without_default.parse(" ".join(default)), min, max, var) + without_default = Option(name, type, None, min, max, var) + option = Option(without_default.name, without_default.type, without_default.parse(default), min, max, var) engine.options[option.name] = option if option.default is not None: From 4cb2b9a85f682091500ccb947dda73e305361e94 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 12 Sep 2023 23:06:30 -0700 Subject: [PATCH 115/250] Simplify UCI option parsing Replace repeated code with a dictionary. --- chess/engine.py | 52 ++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 80312fa19..33c2a3e8c 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1276,6 +1276,7 @@ def __repr__(self) -> str: UCI_OPTION_REGEX = re.compile(r"\s*(name|type|default|min|max|var)\s*") + class UciProtocol(Protocol): """ An implementation of the @@ -1316,46 +1317,31 @@ def line_received(self, engine: UciProtocol, line: str) -> None: self._id(engine, remaining) def _option(self, engine: UciProtocol, arg: str) -> None: - name = "" - type = "" - default = "" - min = None - max = None + current_parameter = None + option_parts: dict[str, str] = {k: "" for k in ["name", "type", "default", "min", "max"]} var = [] - def parse_min_max_value(token: str, which: Literal["min", "max"]) -> Optional[int]: + for token in UCI_OPTION_REGEX.split(arg): + if token == "var" or (token in option_parts and not option_parts[token]): + current_parameter = token + elif current_parameter == "var": + var.append(token) + elif current_parameter: + option_parts[current_parameter] = token + + def parse_min_max_value(option_parts: dict[str, str], which: Literal["min", "max"]) -> Optional[int]: try: - return int(token) + number = option_parts[which] + return int(number) if number else None except ValueError: LOGGER.exception(f"Exception parsing option {which}") return None - current_parameter = None - for token in UCI_OPTION_REGEX.split(arg): - if token == "name" and not name: - current_parameter = "name" - elif token == "type" and not type: - current_parameter = "type" - elif token == "default" and not default: - current_parameter = "default" - elif token == "min" and min is None: - current_parameter = "min" - elif token == "max" and max is None: - current_parameter = "max" - elif token == "var": - current_parameter = "var" - elif current_parameter == "name": - name = token - elif current_parameter == "type": - type = token - elif current_parameter == "default": - default = token - elif current_parameter == "var": - var.append(token) - elif current_parameter == "min": - min = parse_min_max_value(token, "min") - elif current_parameter == "max": - max = parse_min_max_value(token, "max") + name = option_parts["name"] + type = option_parts["type"] + default = option_parts["default"] + min = parse_min_max_value(option_parts, "min") + max = parse_min_max_value(option_parts, "max") without_default = Option(name, type, None, min, max, var) option = Option(without_default.name, without_default.type, without_default.parse(default), min, max, var) From fb991b817718770fdd0291ae4aa962df2ce9cf61 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Tue, 12 Sep 2023 23:28:50 -0700 Subject: [PATCH 116/250] Consolidate UCI option parameter list --- chess/engine.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 33c2a3e8c..126668c7d 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1274,9 +1274,6 @@ def __repr__(self) -> str: return "<{} at {:#x} (state={}, result={}, finished={}>".format(type(self).__name__, id(self), self.state, self.result, self.finished) -UCI_OPTION_REGEX = re.compile(r"\s*(name|type|default|min|max|var)\s*") - - class UciProtocol(Protocol): """ An implementation of the @@ -1321,7 +1318,9 @@ def _option(self, engine: UciProtocol, arg: str) -> None: option_parts: dict[str, str] = {k: "" for k in ["name", "type", "default", "min", "max"]} var = [] - for token in UCI_OPTION_REGEX.split(arg): + parameters = list(option_parts.keys()) + ['var'] + option_regex = fr"\s*({'|'.join(parameters)})\s*" + for token in re.split(option_regex, arg): if token == "var" or (token in option_parts and not option_parts[token]): current_parameter = token elif current_parameter == "var": From f22e3282b69abe37204589829d1eb09267174261 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 13 Sep 2023 00:12:22 -0700 Subject: [PATCH 117/250] Trim whitespace from option line --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 126668c7d..45fe56372 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1320,7 +1320,7 @@ def _option(self, engine: UciProtocol, arg: str) -> None: parameters = list(option_parts.keys()) + ['var'] option_regex = fr"\s*({'|'.join(parameters)})\s*" - for token in re.split(option_regex, arg): + for token in re.split(option_regex, arg.strip()): if token == "var" or (token in option_parts and not option_parts[token]): current_parameter = token elif current_parameter == "var": From f2fd4d3257e7f0cf8078cafa44a25a9d6e4e40c9 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 13 Sep 2023 00:26:11 -0700 Subject: [PATCH 118/250] Strip whitespace when receiving "readyok" --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 45fe56372..9a7a0aa8a 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1387,7 +1387,7 @@ def start(self, engine: UciProtocol) -> None: engine._isready() def line_received(self, engine: UciProtocol, line: str) -> None: - if line == "readyok": + if line.strip() == "readyok": self.result.set_result(None) self.set_finished() else: From 312e477ad24905941d3adbaf8e4b4aaa002e2ba3 Mon Sep 17 00:00:00 2001 From: Josh Giesbrecht Date: Fri, 22 Sep 2023 20:52:21 -0700 Subject: [PATCH 119/250] Update README.rst PicoChess URL seems to have changed - .org domain goes to a domain-for-sale page. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 8ab138666..f4cfd955c 100644 --- a/README.rst +++ b/README.rst @@ -338,7 +338,7 @@ If you like, share interesting things you are using python-chess for, for exampl +------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+ * extensions to build engines (search and evaluation) – https://github.com/Mk-Chan/python-chess-engine-extensions -* a stand-alone chess computer based on DGT board – http://www.picochess.org/ +* a stand-alone chess computer based on DGT board – http://picochess.com/ * a bridge between Lichess API and chess engines – https://github.com/careless25/lichess-bot * a command-line PGN annotator – https://github.com/rpdelaney/python-chess-annotator * an HTTP microservice to render board images – https://github.com/niklasf/web-boardimage From c0bb57204f7f24c8640ba81a819b41ee3e17f253 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Fri, 22 Sep 2023 21:04:30 -0700 Subject: [PATCH 120/250] Update lichess-bot URL in README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 8ab138666..cf249e466 100644 --- a/README.rst +++ b/README.rst @@ -339,7 +339,7 @@ If you like, share interesting things you are using python-chess for, for exampl * extensions to build engines (search and evaluation) – https://github.com/Mk-Chan/python-chess-engine-extensions * a stand-alone chess computer based on DGT board – http://www.picochess.org/ -* a bridge between Lichess API and chess engines – https://github.com/careless25/lichess-bot +* a bridge between Lichess API and chess engines – https://github.com/lichess-bot-devs/lichess-bot * a command-line PGN annotator – https://github.com/rpdelaney/python-chess-annotator * an HTTP microservice to render board images – https://github.com/niklasf/web-boardimage * building a toy chess engine with alpha-beta pruning, piece-square tables, and move ordering – https://healeycodes.com/building-my-own-chess-engine/ From e773cd4eb93519397fe3eea0a8f92cc4662c718c Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 23 Sep 2023 12:45:55 +0200 Subject: [PATCH 121/250] Try explicitly installing and using sphinx-rtd-theme (#1044) --- docs/conf.py | 2 +- docs/requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 22f960575..a6e8a79d9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,4 +49,4 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of built-in themes. -html_theme = "default" +html_theme = "sphinx_rtd_theme" diff --git a/docs/requirements.txt b/docs/requirements.txt index d99b8c473..a63c6a7ca 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ Sphinx==6.1.2 sphinxcontrib-jquery==4.1 +sphinx-rtd-theme==1.3.0 From 97b887ac723d748cbdfe5597971cfd75b520911d Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 30 Sep 2023 18:40:04 +0200 Subject: [PATCH 122/250] Simplify _EmptyMmap.madvise signature --- chess/polyglot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/polyglot.py b/chess/polyglot.py index ac339902c..cdf9b0c2f 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -312,7 +312,7 @@ def size(self) -> int: def close(self) -> None: pass - def madvise(self, option: int, start: int = ..., length: int = ...) -> None: + def madvise(self, option: int) -> None: pass From 2093a7348edf709d1128ad3aed4707c22e6ee739 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 30 Sep 2023 18:49:47 +0200 Subject: [PATCH 123/250] Fix local chess.engine.InfoDict in type hint --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 9a7a0aa8a..b1d3896ab 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2597,7 +2597,7 @@ class AnalysisResult: Automatically stops the analysis when used as a context manager. """ - multipv: List[chess.engine.InfoDict] + multipv: List[InfoDict] """ A list of dictionaries with aggregated information sent by the engine. One item for each root move. From 6f4d35a0bb0f88cbe9f1fccb46a4babc22d098cf Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 30 Sep 2023 19:29:50 +0200 Subject: [PATCH 124/250] Remove some unused loop variables --- chess/gaviota.py | 12 ++++++------ chess/syzygy.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index c2439728f..15371eb19 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -147,7 +147,7 @@ def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: MAX_I = 48 MAX_J = 48 idx = 0 - pp48_idx = [[-1] * MAX_J for i in range(MAX_I)] + pp48_idx = [[-1] * MAX_J for _ in range(MAX_I)] pp48_sq_x = [NOSQUARE] * MAX_PP48_INDEX pp48_sq_y = [NOSQUARE] * MAX_PP48_INDEX @@ -173,7 +173,7 @@ def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[ MAX_I = 48 MAX_J = 48 MAX_K = 48 - ppp48_idx = [[[-1] * MAX_I for j in range(MAX_J)] for k in range(MAX_K)] + ppp48_idx = [[[-1] * MAX_I for _ in range(MAX_J)] for _ in range(MAX_K)] ppp48_sq_x = [NOSQUARE] * MAX_PPP48_INDEX ppp48_sq_y = [NOSQUARE] * MAX_PPP48_INDEX ppp48_sq_z = [NOSQUARE] * MAX_PPP48_INDEX @@ -210,7 +210,7 @@ def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[ def init_aaidx() -> Tuple[List[int], List[List[int]]]: - aaidx = [[-1] * 64 for y in range(64)] + aaidx = [[-1] * 64 for _ in range(64)] aabase = [0] * MAX_AAINDEX idx = 0 @@ -240,7 +240,7 @@ def init_aaa() -> Tuple[List[int], List[List[int]]]: aaa_base[a + 1] = accum # Get aaa_xyz. - aaa_xyz = [[-1] * 3 for idx in range(MAX_AAAINDEX)] + aaa_xyz = [[-1] * 3 for _ in range(MAX_AAAINDEX)] idx = 0 for z in range(64): @@ -319,7 +319,7 @@ def wsq_to_pidx48(pawn: int) -> int: return idx48 def init_ppidx() -> Tuple[List[List[int]], List[int], List[int]]: - ppidx = [[-1] * 48 for i in range(24)] + ppidx = [[-1] * 48 for _ in range(24)] pp_hi24 = [-1] * MAX_PPINDEX pp_lo48 = [-1] * MAX_PPINDEX @@ -379,7 +379,7 @@ def norm_kkindex(x: chess.Square, y: chess.Square) -> Tuple[int, int]: return x, y def init_kkidx() -> Tuple[List[List[int]], List[int], List[int]]: - kkidx = [[-1] * 64 for x in range(64)] + kkidx = [[-1] * 64 for _ in range(64)] bksq = [-1] * MAX_KKINDEX wksq = [-1] * MAX_KKINDEX idx = 0 diff --git a/chess/syzygy.py b/chess/syzygy.py index 96a17e921..8953b8e6b 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1257,7 +1257,7 @@ def init_table_dtz(self) -> None: self.norm = [0 for _ in range(self.num)] self.tb_size = [0, 0, 0, 0] self.size = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - self.files = [PawnFileDataDtz() for f in range(4)] + self.files = [PawnFileDataDtz() for _ in range(4)] files = 4 if self.data[4] & 0x02 else 1 From 15e3584ff65c46c6b1cecaf14b6fc25868587a93 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 30 Sep 2023 19:44:41 +0200 Subject: [PATCH 125/250] Provide type hints for empty lists --- chess/__init__.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 65719fd5c..a9328a04b 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -412,8 +412,8 @@ def _carry_rippler(mask: Bitboard) -> Iterator[Bitboard]: break def _attack_table(deltas: List[int]) -> Tuple[List[Bitboard], List[Dict[Bitboard, Bitboard]]]: - mask_table = [] - attack_table = [] + mask_table: List[Bitboard] = [] + attack_table: List[Dict[Bitboard, Bitboard]] = [] for square in SQUARES: attacks = {} @@ -433,9 +433,9 @@ def _attack_table(deltas: List[int]) -> Tuple[List[Bitboard], List[Dict[Bitboard def _rays() -> List[List[Bitboard]]: - rays = [] + rays: List[List[Bitboard]] = [] for a, bb_a in enumerate(BB_SQUARES): - rays_row = [] + rays_row: List[Bitboard] = [] for b, bb_b in enumerate(BB_SQUARES): if BB_DIAG_ATTACKS[a][0] & bb_b: rays_row.append((BB_DIAG_ATTACKS[a][0] & BB_DIAG_ATTACKS[b][0]) | bb_a | bb_b) @@ -961,7 +961,7 @@ def board_fen(self, *, promoted: Optional[bool] = False) -> str: Gets the board FEN (e.g., ``rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR``). """ - builder = [] + builder: List[str] = [] empty = 0 for square in SQUARES_180: @@ -1056,7 +1056,7 @@ def piece_map(self, *, mask: Bitboard = BB_ALL) -> Dict[Square, Piece]: """ Gets a dictionary of :class:`pieces ` by square index. """ - result = {} + result: Dict[Square, Piece] = {} for square in scan_reversed(self.occupied & mask): result[square] = typing.cast(Piece, self.piece_at(square)) return result @@ -1225,7 +1225,7 @@ def __repr__(self) -> str: return f"{type(self).__name__}({self.board_fen()!r})" def __str__(self) -> str: - builder = [] + builder: List[str] = [] for square in SQUARES_180: piece = self.piece_at(square) @@ -1251,7 +1251,7 @@ def unicode(self, *, invert_color: bool = False, borders: bool = False, empty_sq :param invert_color: Invert color of the Unicode pieces. :param borders: Show borders and a coordinate margin. """ - builder = [] + builder: List[str] = [] for rank_index in (range(7, -1, -1) if orientation else range(8)): if borders: builder.append(" ") @@ -2094,7 +2094,7 @@ def can_claim_threefold_repetition(self) -> bool: transpositions.update((transposition_key, )) # Count positions. - switchyard = [] + switchyard: List[Move] = [] while self.move_stack: move = self.pop() switchyard.append(move) @@ -2147,7 +2147,7 @@ def is_repetition(self, count: int = 3) -> bool: # Check full replay. transposition_key = self._transposition_key() - switchyard = [] + switchyard: List[Move] = [] try: while True: @@ -2343,7 +2343,7 @@ def castling_shredder_fen(self) -> str: if not castling_rights: return "-" - builder = [] + builder: List[str] = [] for square in scan_reversed(castling_rights & BB_RANK_1): builder.append(FILE_NAMES[square_file(square)].upper()) @@ -2354,7 +2354,7 @@ def castling_shredder_fen(self) -> str: return "".join(builder) def castling_xfen(self) -> str: - builder = [] + builder: List[str] = [] for color in COLORS: king = self.king(color) @@ -2615,7 +2615,7 @@ def chess960_pos(self, *, ignore_turn: bool = False, ignore_castling: bool = Fal return super().chess960_pos() def _epd_operations(self, operations: Mapping[str, Union[None, str, int, float, Move, Iterable[Move]]]) -> str: - epd = [] + epd: List[str] = [] first_op = True for opcode, operand in operations.items(): @@ -2786,7 +2786,7 @@ def _parse_epd_ops(self: BoardT, operation_part: str, make_board: Callable[[], B if opcode == "pv": # A variation. - variation = [] + variation: List[Move] = [] for token in operand.split(): move = position.parse_xboard(token) variation.append(move) @@ -2963,7 +2963,7 @@ def variation_san(self, variation: Iterable[Move]) -> str: :raises: :exc:`IllegalMoveError` if any moves in the sequence are illegal. """ board = self.copy(stack=False) - san = [] + san: List[str] = [] for move in variation: if not board.is_legal(move): @@ -3781,7 +3781,7 @@ def __contains__(self, move: Move) -> bool: return self.board.is_pseudo_legal(move) def __repr__(self) -> str: - builder = [] + builder: List[str] = [] for move in self: if self.board.is_legal(move): @@ -3898,7 +3898,7 @@ class SquareSet: def __init__(self, squares: IntoSquareSet = BB_EMPTY) -> None: try: - self.mask = squares.__int__() & BB_ALL # type: ignore + self.mask: Bitboard = squares.__int__() & BB_ALL # type: ignore return except AttributeError: self.mask = 0 @@ -4095,7 +4095,7 @@ def __repr__(self) -> str: return f"SquareSet({self.mask:#021_x})" def __str__(self) -> str: - builder = [] + builder: List[str] = [] for square in SQUARES_180: mask = BB_SQUARES[square] From e57312294bdce09d08714e83f74e274b94f18597 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 1 Oct 2023 22:04:14 +0200 Subject: [PATCH 126/250] Bump actions/checkout to v4 --- .github/workflows/codeql.yml | 2 +- .github/workflows/test.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a37e82933..cd5d5a2d8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -11,7 +11,7 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: github/codeql-action/init@v2 with: languages: python diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 184092752..637880b51 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -21,7 +21,7 @@ jobs: perft: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.11" @@ -42,7 +42,7 @@ jobs: python-version: ["3.9", "3.10", "3.11"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -53,7 +53,7 @@ jobs: readme: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.11" From 86f5f55846caaec1c22bc40a2b53d42b06916617 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 1 Oct 2023 22:10:32 +0200 Subject: [PATCH 127/250] Fix map_idx type --- chess/syzygy.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 8953b8e6b..6a0efdef5 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -12,7 +12,7 @@ import chess from types import TracebackType -from typing import Deque, Dict, Iterable, Iterator, List, Optional, Tuple, Type, TypeVar, Union +from typing import Deque, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type, TypeVar, Union UINT64_BE = struct.Struct(">Q") @@ -368,7 +368,7 @@ def is_tablename(name: str, *, one_king: bool = True, piece_count: Optional[int] def tablenames(*, one_king: bool = True, piece_count: int = 6) -> Iterator[str]: first = "K" if one_king else "P" - targets = [] + targets: List[str] = [] white_pieces = piece_count - 2 black_pieces = 0 @@ -411,7 +411,7 @@ def _dependencies(target: str, *, one_king: bool = True) -> Iterator[str]: def dependencies(target: str, *, one_king: bool = True) -> Iterator[str]: - closed = set() + closed: Set[str] = set() if one_king: closed.add("KvK") @@ -422,7 +422,7 @@ def dependencies(target: str, *, one_king: bool = True) -> Iterator[str]: def all_dependencies(targets: Iterable[str], *, one_king: bool = True) -> Iterator[str]: - closed = set() + closed: Set[str] = set() if one_king: closed.add("KvK") @@ -684,10 +684,7 @@ def set_norm_piece(self, norm: List[int], pieces: List[int]) -> None: i += norm[i] def calc_factors_piece(self, factor: List[int], order: int, norm: List[int]) -> int: - if not self.variant.connected_kings: - PIVFAC = [31332, 28056, 462] - else: - PIVFAC = [31332, 0, 518, 278] + PIVFAC = [31332, 0, 518, 278] if self.variant.connected_kings else [31332, 28056, 462] n = 64 - norm[0] @@ -1310,7 +1307,7 @@ def init_table_dtz(self) -> None: p_data = self._next self.flags.append(self._flags) - self.map_idx = [] + self.map_idx: List[List[int]] = [] self.p_map = p_data for f in range(files): self.map_idx.append([]) From 1dd3e1e11e637113f42ad29ace841876029d7a81 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 1 Oct 2023 22:19:54 +0200 Subject: [PATCH 128/250] Make also mypy happy --- chess/svg.py | 2 +- chess/syzygy.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index 3e034ce30..d3d19e89e 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -434,7 +434,7 @@ def board(board: Optional[chess.BaseBoard] = None, *, }) # Render selected squares. - if squares is not None and square in squares: + if square in squares: ET.SubElement(svg, "use", _attrs({ "href": "#xx", "xlink:href": "#xx", diff --git a/chess/syzygy.py b/chess/syzygy.py index 6a0efdef5..e1fe07eb7 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1261,7 +1261,7 @@ def init_table_dtz(self) -> None: p_data = 5 if not self.has_pawns: - self.map_idx = [[0, 0, 0, 0]] + self.map_idx: List[List[int]] = [[0, 0, 0, 0]] self.setup_pieces_piece_dtz(p_data, 0) p_data += self.num + 1 @@ -1307,7 +1307,7 @@ def init_table_dtz(self) -> None: p_data = self._next self.flags.append(self._flags) - self.map_idx: List[List[int]] = [] + self.map_idx = [] self.p_map = p_data for f in range(files): self.map_idx.append([]) From 3a99f1bfc76185c81632b00c5a700b3b2a62fd4b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 8 Oct 2023 17:39:43 +0200 Subject: [PATCH 129/250] Declare chess.popcount in pyright compatible way --- chess/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index a9328a04b..49ec73d9c 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -297,8 +297,12 @@ def scan_reversed(bb: Bitboard) -> Iterator[Square]: yield r bb ^= BB_SQUARES[r] -# Python 3.10 or fallback. -popcount: Callable[[Bitboard], int] = getattr(int, "bit_count", lambda bb: bin(bb).count("1")) +try: + # Python 3.10 + popcount = Bitboard.bit_count +except AttributeError: + def popcount(self: Bitboard) -> int: + return bin(self).count("1") def flip_vertical(bb: Bitboard) -> Bitboard: # https://www.chessprogramming.org/Flipping_Mirroring_and_Rotating#FlipVertically From 99eeeae4d2eed95939f6c52eae9d3418fd1c8a8e Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 8 Oct 2023 19:08:01 +0200 Subject: [PATCH 130/250] Revert "Declare chess.popcount in pyright compatible way" This reverts commit 3a99f1bfc76185c81632b00c5a700b3b2a62fd4b. --- chess/__init__.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 49ec73d9c..a9328a04b 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -297,12 +297,8 @@ def scan_reversed(bb: Bitboard) -> Iterator[Square]: yield r bb ^= BB_SQUARES[r] -try: - # Python 3.10 - popcount = Bitboard.bit_count -except AttributeError: - def popcount(self: Bitboard) -> int: - return bin(self).count("1") +# Python 3.10 or fallback. +popcount: Callable[[Bitboard], int] = getattr(int, "bit_count", lambda bb: bin(bb).count("1")) def flip_vertical(bb: Bitboard) -> Bitboard: # https://www.chessprogramming.org/Flipping_Mirroring_and_Rotating#FlipVertically From 4a6dd9a89b7810312ab4ea1cf255d1a501ae09ca Mon Sep 17 00:00:00 2001 From: Rahul Saini <137695929+ProgramR4732@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:24:56 +0530 Subject: [PATCH 131/250] Removed unnecessary indentation blocks and updated conditional statements. --- release.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/release.py b/release.py index d27ddf04e..f2f7d81fa 100755 --- a/release.py +++ b/release.py @@ -10,7 +10,7 @@ def system(command): print(command) exit_code = os.system(command) - if exit_code != 0: + if exit_code: sys.exit(exit_code) @@ -21,7 +21,7 @@ def check_git(): system("git fetch origin") behind = int(subprocess.check_output(["git", "rev-list", "--count", "master..origin/master"])) - if behind > 0: + if behind: print(f"master is {behind} commit(s) behind origin/master") sys.exit(1) @@ -65,15 +65,14 @@ def tag_and_push(): release_txt.write(headline + os.linesep) for line in changelog_file: - if not first_section: - if line.startswith("-------"): - first_section = True + if line.startswith("-------") and not first_section: + first_section = True else: if line.startswith("-------"): break - else: - if not prev_line.startswith("------"): - release_txt.write(prev_line) + + if not prev_line.startswith("------"): + release_txt.write(prev_line) prev_line = line From 615a21b4ca7679c51388159324f2a9545868f6f1 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 15 Oct 2023 19:02:54 +0200 Subject: [PATCH 132/250] Link chess-playground --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index ee3b315e7..07e0e3251 100644 --- a/README.rst +++ b/README.rst @@ -350,6 +350,7 @@ If you like, share interesting things you are using python-chess for, for exampl * Django Rest Framework API for multiplayer chess – https://github.com/WorkShoft/capablanca-api * a `browser based PGN viewer `_ written in PyScript – https://github.com/nmstoker/ChessMatchViewer * an accessible chessboard that allows blind and visually impaired players to play chess against Stockfish – https://github.com/blindpandas/chessmart +* analyse games to extract various statistics – https://github.com/mvrozanti/chess-playground Prior art From 2b754a25854b41c68a847c5c36439f2eb1cdffb2 Mon Sep 17 00:00:00 2001 From: anonymousdouble <112695649+anonymousdouble@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:15:29 +1100 Subject: [PATCH 133/250] Update gaviota.py refactor with chain constant value assignment to make code more Pythonic, concise and efficient. --- chess/gaviota.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 15371eb19..39173b593 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -144,8 +144,7 @@ def init_flipt() -> List[List[int]]: def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: - MAX_I = 48 - MAX_J = 48 + MAX_I = MAX_J = 48 idx = 0 pp48_idx = [[-1] * MAX_J for _ in range(MAX_I)] pp48_sq_x = [NOSQUARE] * MAX_PP48_INDEX @@ -170,9 +169,7 @@ def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[int]]: - MAX_I = 48 - MAX_J = 48 - MAX_K = 48 + MAX_I = MAX_J = MAX_K = 48 ppp48_idx = [[[-1] * MAX_I for _ in range(MAX_J)] for _ in range(MAX_K)] ppp48_sq_x = [NOSQUARE] * MAX_PPP48_INDEX ppp48_sq_y = [NOSQUARE] * MAX_PPP48_INDEX From a64f78eb42b48a7a1f79a4fb2134c649d4dea4c2 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:07:17 +0100 Subject: [PATCH 134/250] Try to test with Ubuntu engine packages in CI --- .github/workflows/setup-ubuntu-latest.sh | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/setup-ubuntu-latest.sh b/.github/workflows/setup-ubuntu-latest.sh index 8954c8f0c..fae35b61a 100755 --- a/.github/workflows/setup-ubuntu-latest.sh +++ b/.github/workflows/setup-ubuntu-latest.sh @@ -1,19 +1,10 @@ #!/bin/sh -e # Stockfish -wget https://files.stockfishchess.org/archive/Stockfish%2011/stockfish-11-linux.zip -unzip stockfish-11-linux.zip -mkdir -p bin -cp stockfish-11-linux/Linux/stockfish_20011801_x64_bmi2 bin/stockfish -chmod +x bin/stockfish -echo "`pwd`/bin" >> $GITHUB_PATH +sudo apt-get install -y stockfish # Crafty -git clone https://github.com/lazydroid/crafty-chess --depth 1 -cd crafty-chess -make unix-gcc -pwd >> $GITHUB_PATH -cd .. +sudo apt-get install -y crafty # Gaviota libgtb git clone https://github.com/michiguel/Gaviota-Tablebases.git --depth 1 From 0082833d30ac98cae1b272e220f56e0797f1187c Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:17:41 +0100 Subject: [PATCH 135/250] Try to download Stockfish release in Windows CI --- .github/workflows/setup-windows-latest.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/setup-windows-latest.sh b/.github/workflows/setup-windows-latest.sh index 685ead65a..f92bd9059 100755 --- a/.github/workflows/setup-windows-latest.sh +++ b/.github/workflows/setup-windows-latest.sh @@ -2,11 +2,11 @@ echo Download ... choco install wget -wget https://files.stockfishchess.org/archive/Stockfish%2011/stockfish-11-win.zip +wget https://github.com/official-stockfish/Stockfish/releases/download/sf_16/stockfish-windows-x86-64-avx2.zip echo Unzip .. -7z e stockfish-11-win.zip stockfish-11-win/Windows/*.exe +7z e stockfish-windows-x86-64-avx2.zip /stockfish/stockfish-windows-x86-64-avx2.exe echo Setup path ... -mv stockfish_20011801_x64_bmi2.exe stockfish.exe +mv stockfish-windows-x86-64-avx2.exe stockfish.exe pwd >> $GITHUB_PATH From 8a70a2c90f228826f34f9bf2629de86e750ab796 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:21:40 +0100 Subject: [PATCH 136/250] Try to fix Stockfish zip extract --- .github/workflows/setup-windows-latest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/setup-windows-latest.sh b/.github/workflows/setup-windows-latest.sh index f92bd9059..815eb0db2 100755 --- a/.github/workflows/setup-windows-latest.sh +++ b/.github/workflows/setup-windows-latest.sh @@ -5,7 +5,7 @@ choco install wget wget https://github.com/official-stockfish/Stockfish/releases/download/sf_16/stockfish-windows-x86-64-avx2.zip echo Unzip .. -7z e stockfish-windows-x86-64-avx2.zip /stockfish/stockfish-windows-x86-64-avx2.exe +7z e stockfish-windows-x86-64-avx2.zip stockfish/stockfish-windows-x86-64-avx2.exe echo Setup path ... mv stockfish-windows-x86-64-avx2.exe stockfish.exe From 2477ae8f4f36ce4ff872383a47ec2cf2e2eb6cf7 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:28:48 +0100 Subject: [PATCH 137/250] Fix typing involving PathLike --- chess/polyglot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chess/polyglot.py b/chess/polyglot.py index cdf9b0c2f..bf4fa0cd1 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -11,7 +11,7 @@ from typing import Callable, Container, Iterator, List, NamedTuple, Optional, Type, Union -PathLike = Union[str, bytes, os.PathLike] +StrOrBytesPath = Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] ENTRY_STRUCT = struct.Struct(">QHHI") @@ -323,7 +323,7 @@ def _randint(rng: Optional[random.Random], a: int, b: int) -> int: class MemoryMappedReader: """Maps a Polyglot opening book to memory.""" - def __init__(self, filename: PathLike) -> None: + def __init__(self, filename: StrOrBytesPath) -> None: fd = os.open(filename, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) try: self.mmap: Union[mmap.mmap, _EmptyMmap] = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) @@ -500,7 +500,7 @@ def close(self) -> None: self.mmap.close() -def open_reader(path: PathLike) -> MemoryMappedReader: +def open_reader(path: StrOrBytesPath) -> MemoryMappedReader: """ Creates a reader for the file at the given path. From 62148665fd966c6047e2560bc289763ddca556af Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:33:05 +0100 Subject: [PATCH 138/250] Test also with Python 3.12 --- .github/workflows/test.yml | 8 ++++---- setup.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 637880b51..576d8b491 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.12" - run: pip install -e . - run: python examples/perft/perft.py -t 1 examples/perft/random.perft --max-nodes 10000 - run: python examples/perft/perft.py -t 1 examples/perft/chess960.perft --max-nodes 100000 @@ -39,7 +39,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: "3.12" - run: sudo apt-get update && sudo apt-get install -y docutils-common - run: python setup.py --long-description | rst2html --strict --no-raw > /dev/null - run: pip install -e . diff --git a/setup.py b/setup.py index 8c397e456..b825adb44 100755 --- a/setup.py +++ b/setup.py @@ -82,6 +82,7 @@ def read_description(): "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Games/Entertainment :: Board Games", "Topic :: Games/Entertainment :: Turn Based Strategy", "Topic :: Software Development :: Libraries :: Python Modules", From 0946d784bfead47bfba88ca185b2ed626fd31bbd Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:34:51 +0100 Subject: [PATCH 139/250] Work around PathLike not subscriptable on Python 3.8 --- chess/polyglot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/polyglot.py b/chess/polyglot.py index bf4fa0cd1..44a68caa5 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -11,7 +11,7 @@ from typing import Callable, Container, Iterator, List, NamedTuple, Optional, Type, Union -StrOrBytesPath = Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] +StrOrBytesPath = Union[str, bytes, "os.PathLike[str]", "os.PathLike[bytes]"] ENTRY_STRUCT = struct.Struct(">QHHI") From c5c388292c7986405ebbe4813b1691299bf3e900 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 12:37:49 +0100 Subject: [PATCH 140/250] Bump version requirement and copyright year --- README.rst | 2 +- docs/conf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 07e0e3251..7a677a451 100644 --- a/README.rst +++ b/README.rst @@ -59,7 +59,7 @@ python-chess: Installing ---------- -Requires Python 3.7+. Download and install the latest release: +Requires Python 3.8+. Download and install the latest release: :: diff --git a/docs/conf.py b/docs/conf.py index a6e8a79d9..98e926efa 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,7 +34,7 @@ # General information about the project. project = "python-chess" -copyright = "2014–2023, Niklas Fiekas" +copyright = "2014–2024, Niklas Fiekas" # The version. version = chess.__version__ From cd7f5958289dd08156436a1f84b9ea03cb1f75a1 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 1 Jan 2024 14:48:01 +0100 Subject: [PATCH 141/250] Update to CodeQL 3 --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cd5d5a2d8..bc991c885 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -12,7 +12,7 @@ jobs: security-events: write steps: - uses: actions/checkout@v4 - - uses: github/codeql-action/init@v2 + - uses: github/codeql-action/init@v3 with: languages: python - - uses: github/codeql-action/analyze@v2 + - uses: github/codeql-action/analyze@v3 From 65f6d7d7a2229be1c6c9051182d299404b0186d5 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 21 Feb 2024 03:23:07 -0800 Subject: [PATCH 142/250] Add support for multiple comments per move --- chess/pgn.py | 108 +++++++++++++++++++++++++++++---------------------- test.py | 58 +++++++++++++-------------- 2 files changed, 91 insertions(+), 75 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 55eddbc29..65ef0e6d5 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -197,24 +197,24 @@ class GameNode(abc.ABC): variations: List[ChildNode] """A list of child nodes.""" - comment: str + comments: list[str] """ - A comment that goes behind the move leading to this node. Comments + Comments that go behind the move leading to this node. Comments that occur before any moves are assigned to the root node. """ - starting_comment: str + starting_comments: list[str] nags: Set[int] - def __init__(self, *, comment: str = "") -> None: + def __init__(self, *, comment: Union[str, list[str]] = "") -> None: self.parent = None self.move = None self.variations = [] - self.comment = comment + self.comment = comment if isinstance(comment, list) else [comment] if comment else [] # Deprecated: These should be properties of ChildNode, but need to # remain here for backwards compatibility. - self.starting_comment = "" + self.starting_comment: list[str] = [] self.nags = set() @abc.abstractmethod @@ -386,7 +386,7 @@ def remove_variation(self, move: Union[int, chess.Move, GameNode]) -> None: """Removes a variation.""" self.variations.remove(self.variation(move)) - def add_variation(self, move: chess.Move, *, comment: str = "", starting_comment: str = "", nags: Iterable[int] = []) -> ChildNode: + def add_variation(self, move: chess.Move, *, comment: Union[str, list[str]] = "", starting_comment: Union[str, list[str]] = "", nags: Iterable[int] = []) -> ChildNode: """Creates a child node with the given attributes.""" # Instanciate ChildNode only in this method. return ChildNode(self, move, comment=comment, starting_comment=starting_comment, nags=nags) @@ -417,7 +417,7 @@ def mainline_moves(self) -> Mainline[chess.Move]: """Returns an iterable over the main moves after this node.""" return Mainline(self, lambda node: node.move) - def add_line(self, moves: Iterable[chess.Move], *, comment: str = "", starting_comment: str = "", nags: Iterable[int] = []) -> GameNode: + def add_line(self, moves: Iterable[chess.Move], *, comment: Union[str, list[str]] = "", starting_comment: Union[str, list[str]] = "", nags: Iterable[int] = []) -> GameNode: """ Creates a sequence of child nodes for the given list of moves. Adds *comment* and *nags* to the last node of the line and returns it. @@ -431,9 +431,12 @@ def add_line(self, moves: Iterable[chess.Move], *, comment: str = "", starting_c # Merge comment and NAGs. if node.comment: - node.comment += " " + comment + if isinstance(comment, str): + node.comment.append(comment) + else: + node.comment.extend(comment) else: - node.comment = comment + node.comment = comment if isinstance(comment, list) else [comment] if comment else [] node.nags.update(nags) @@ -446,7 +449,7 @@ def eval(self) -> Optional[chess.engine.PovScore]: Complexity is `O(n)`. """ - match = EVAL_REGEX.search(self.comment) + match = EVAL_REGEX.search(" ".join(self.comment)) if not match: return None @@ -472,7 +475,7 @@ def eval_depth(self) -> Optional[int]: Complexity is `O(1)`. """ - match = EVAL_REGEX.search(self.comment) + match = EVAL_REGEX.search(" ".join(self.comment)) return int(match.group("depth")) if match and match.group("depth") else None def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] = None) -> None: @@ -489,12 +492,16 @@ def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] elif score.white().mate(): eval = f"[%eval #{score.white().mate()}{depth_suffix}]" - self.comment, found = EVAL_REGEX.subn(_condense_affix(eval), self.comment, count=1) + found = 0 + for index in range(len(self.comment)): + self.comment[index], found = EVAL_REGEX.subn(_condense_affix(eval), self.comment[index], count=1) + if found: + break + + self.comment = list(filter(None, self.comment)) if not found and eval: - if self.comment and not self.comment.endswith(" "): - self.comment += " " - self.comment += eval + self.comment.append(eval) def arrows(self) -> List[chess.svg.Arrow]: """ @@ -504,7 +511,7 @@ def arrows(self) -> List[chess.svg.Arrow]: Returns a list of :class:`arrows `. """ arrows = [] - for match in ARROWS_REGEX.finditer(self.comment): + for match in ARROWS_REGEX.finditer(" ".join(self.comment)): for group in match.group("arrows").split(","): arrows.append(chess.svg.Arrow.from_pgn(group)) @@ -526,7 +533,10 @@ def set_arrows(self, arrows: Iterable[Union[chess.svg.Arrow, Tuple[Square, Squar pass (csl if arrow.tail == arrow.head else cal).append(arrow.pgn()) # type: ignore - self.comment = ARROWS_REGEX.sub(_condense_affix(""), self.comment) + for index in range(len(self.comment)): + self.comment[index] = ARROWS_REGEX.sub(_condense_affix(""), self.comment[index]) + + self.comment = list(filter(None, self.comment)) prefix = "" if csl: @@ -534,10 +544,8 @@ def set_arrows(self, arrows: Iterable[Union[chess.svg.Arrow, Tuple[Square, Squar if cal: prefix += f"[%cal {','.join(cal)}]" - if prefix and self.comment and not self.comment.startswith(" ") and not self.comment.startswith("\n"): - self.comment = prefix + " " + self.comment - else: - self.comment = prefix + self.comment + if prefix: + self.comment.insert(0, prefix) def clock(self) -> Optional[float]: """ @@ -547,7 +555,7 @@ def clock(self) -> Optional[float]: Returns the player's remaining time to the next time control after this move, in seconds. """ - match = CLOCK_REGEX.search(self.comment) + match = CLOCK_REGEX.search(" ".join(self.comment)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -566,12 +574,16 @@ def set_clock(self, seconds: Optional[float]) -> None: seconds_part = f"{seconds:06.3f}".rstrip("0").rstrip(".") clk = f"[%clk {hours:d}:{minutes:02d}:{seconds_part}]" - self.comment, found = CLOCK_REGEX.subn(_condense_affix(clk), self.comment, count=1) + found = 0 + for index in range(len(self.comment)): + self.comment[index], found = CLOCK_REGEX.subn(_condense_affix(clk), self.comment[index], count=1) + if found: + break + + self.comment = list(filter(None, self.comment)) if not found and clk: - if self.comment and not self.comment.endswith(" ") and not self.comment.endswith("\n"): - self.comment += " " - self.comment += clk + self.comment.append(clk) def emt(self) -> Optional[float]: """ @@ -581,7 +593,7 @@ def emt(self) -> Optional[float]: Returns the player's elapsed move time use for the comment of this move, in seconds. """ - match = EMT_REGEX.search(self.comment) + match = EMT_REGEX.search(" ".join(self.comment)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -600,12 +612,16 @@ def set_emt(self, seconds: Optional[float]) -> None: seconds_part = f"{seconds:06.3f}".rstrip("0").rstrip(".") emt = f"[%emt {hours:d}:{minutes:02d}:{seconds_part}]" - self.comment, found = EMT_REGEX.subn(_condense_affix(emt), self.comment, count=1) + found = 0 + for index in range(len(self.comment)): + self.comment[index], found = EMT_REGEX.subn(_condense_affix(emt), self.comment[index], count=1) + if found: + break + + self.comment = list(filter(None, self.comment)) if not found and emt: - if self.comment and not self.comment.endswith(" ") and not self.comment.endswith("\n"): - self.comment += " " - self.comment += emt + self.comment.append(emt) @abc.abstractmethod def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: @@ -661,7 +677,7 @@ class ChildNode(GameNode): move: chess.Move """The move leading to this node.""" - starting_comment: str + starting_comment: list[str] """ A comment for the start of a variation. Only nodes that actually start a variation (:func:`~chess.pgn.GameNode.starts_variation()` @@ -675,14 +691,14 @@ class ChildNode(GameNode): node of the game will never have NAGs. """ - def __init__(self, parent: GameNode, move: chess.Move, *, comment: str = "", starting_comment: str = "", nags: Iterable[int] = []) -> None: + def __init__(self, parent: GameNode, move: chess.Move, *, comment: Union[str, list[str]] = "", starting_comment: Union[str, list[str]] = "", nags: Iterable[int] = []) -> None: super().__init__(comment=comment) self.parent = parent self.move = move self.parent.variations.append(self) self.nags.update(nags) - self.starting_comment = starting_comment + self.starting_comment = starting_comment if isinstance(starting_comment, list) else [starting_comment] if starting_comment else [] def board(self) -> chess.Board: stack: List[chess.Move] = [] @@ -1134,7 +1150,7 @@ def visit_board(self, board: chess.Board) -> None: """ pass - def visit_comment(self, comment: str) -> None: + def visit_comment(self, comment: list[str]) -> None: """Called for each comment.""" pass @@ -1188,7 +1204,7 @@ def begin_game(self) -> None: self.game: GameT = self.Game() self.variation_stack: List[GameNode] = [self.game] - self.starting_comment = "" + self.starting_comment: list[str] = [] self.in_variation = False def begin_headers(self) -> Headers: @@ -1213,22 +1229,22 @@ def visit_result(self, result: str) -> None: if self.game.headers.get("Result", "*") == "*": self.game.headers["Result"] = result - def visit_comment(self, comment: str) -> None: + def visit_comment(self, comment: list[str]) -> None: if self.in_variation or (self.variation_stack[-1].parent is None and self.variation_stack[-1].is_end()): # Add as a comment for the current node if in the middle of # a variation. Add as a comment for the game if the comment # starts before any move. - new_comment = [self.variation_stack[-1].comment, comment] - self.variation_stack[-1].comment = " ".join(filter(None, new_comment)) + new_comment = self.variation_stack[-1].comment + comment + self.variation_stack[-1].comment = list(filter(None, new_comment)) else: # Otherwise, it is a starting comment. - new_comment = [self.starting_comment, comment] - self.starting_comment = " ".join(filter(None, new_comment)) + new_comment = self.starting_comment + comment + self.starting_comment = list(filter(None, new_comment)) def visit_move(self, board: chess.Board, move: chess.Move) -> None: self.variation_stack[-1] = self.variation_stack[-1].add_variation(move) self.variation_stack[-1].starting_comment = self.starting_comment - self.starting_comment = "" + self.starting_comment = [] self.in_variation = True def handle_error(self, error: Exception) -> None: @@ -1396,9 +1412,9 @@ def end_variation(self) -> None: self.write_token(") ") self.force_movenumber = True - def visit_comment(self, comment: str) -> None: + def visit_comment(self, comment: list[str]) -> None: if self.comments and (self.variations or not self.variation_depth): - self.write_token("{ " + comment.replace("}", "").strip() + " } ") + self.write_token(" ".join("{ " + single_comment.replace("}", "").strip() + " }" for single_comment in comment) + " ") self.force_movenumber = True def visit_nag(self, nag: int) -> None: @@ -1693,7 +1709,7 @@ def read_game(handle: TextIO, *, Visitor: Any = GameBuilder) -> Any: line = line[close_index + 1:] if not skip_variation_depth: - visitor.visit_comment("".join(comment_lines)) + visitor.visit_comment(["".join(comment_lines)]) # Continue with the current line. fresh_line = False diff --git a/test.py b/test.py index e1d0d50c5..d3961cc6b 100755 --- a/test.py +++ b/test.py @@ -2078,29 +2078,29 @@ class PgnTestCase(unittest.TestCase): def test_exporter(self): game = chess.pgn.Game() - game.comment = "Test game:" + game.comment = ["Test game:"] game.headers["Result"] = "*" game.headers["VeryLongHeader"] = "This is a very long header, much wider than the 80 columns that PGNs are formatted with by default" e4 = game.add_variation(game.board().parse_san("e4")) - e4.comment = "Scandinavian Defense:" + e4.comment = ["Scandinavian Defense:"] e4_d5 = e4.add_variation(e4.board().parse_san("d5")) e4_h5 = e4.add_variation(e4.board().parse_san("h5")) e4_h5.nags.add(chess.pgn.NAG_MISTAKE) - e4_h5.starting_comment = "This" - e4_h5.comment = "is nonsense" + e4_h5.starting_comment = ["This"] + e4_h5.comment = ["is nonsense"] e4_e5 = e4.add_variation(e4.board().parse_san("e5")) e4_e5_Qf3 = e4_e5.add_variation(e4_e5.board().parse_san("Qf3")) e4_e5_Qf3.nags.add(chess.pgn.NAG_MISTAKE) e4_c5 = e4.add_variation(e4.board().parse_san("c5")) - e4_c5.comment = "Sicilian" + e4_c5.comment = ["Sicilian"] e4_d5_exd5 = e4_d5.add_main_variation(e4_d5.board().parse_san("exd5")) - e4_d5_exd5.comment = "Best" + e4_d5_exd5.comment = ["Best"] # Test string exporter with various options. exporter = chess.pgn.StringExporter(headers=False, comments=False, variations=False) @@ -2229,7 +2229,7 @@ def test_comment_at_eol(self): # Make sure the comment for the second variation is there. self.assertIn(5, node[1].nags) - self.assertEqual(node[1].comment, "\n/\\ Ne7, c6") + self.assertEqual(node[1].comment, ["\n/\\ Ne7, c6"]) def test_promotion_without_equals(self): # Example game from https://github.com/rozim/ChessData as originally @@ -2317,12 +2317,12 @@ def test_variation_stack(self): def test_game_starting_comment(self): pgn = io.StringIO("{ Game starting comment } 1. d3") game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, "Game starting comment") + self.assertEqual(game.comment, ["Game starting comment"]) self.assertEqual(game[0].san(), "d3") pgn = io.StringIO("{ Empty game, but has a comment }") game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, "Empty game, but has a comment") + self.assertEqual(game.comment, ["Empty game, but has a comment"]) def test_game_starting_variation(self): pgn = io.StringIO(textwrap.dedent("""\ @@ -2330,7 +2330,7 @@ def test_game_starting_variation(self): """)) game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, "Start of game") + self.assertEqual(game.comment, ["Start of game"]) node = game[0] self.assertEqual(node.move, chess.Move.from_uci("e2e4")) @@ -2340,7 +2340,7 @@ def test_game_starting_variation(self): node = game[1] self.assertEqual(node.move, chess.Move.from_uci("d2d4")) self.assertFalse(node.comment) - self.assertEqual(node.starting_comment, "Start of variation") + self.assertEqual(node.starting_comment, ["Start of variation"]) def test_annotation_symbols(self): pgn = io.StringIO("1. b4?! g6 2. Bb2 Nc6? 3. Bxh8!!") @@ -2685,12 +2685,12 @@ def test_add_line(self): tail = game.add_line(moves, starting_comment="start", comment="end", nags=(17, 42)) self.assertEqual(tail.parent.move, chess.Move.from_uci("g1f3")) - self.assertEqual(tail.parent.starting_comment, "start") - self.assertEqual(tail.parent.comment, "") + self.assertEqual(tail.parent.starting_comment, ["start"]) + self.assertEqual(tail.parent.comment, []) self.assertEqual(len(tail.parent.nags), 0) self.assertEqual(tail.move, chess.Move.from_uci("d7d5")) - self.assertEqual(tail.comment, "end") + self.assertEqual(tail.comment, ["end"]) self.assertIn(42, tail.nags) def test_mainline(self): @@ -2820,27 +2820,27 @@ def test_recursion(self): def test_annotations(self): game = chess.pgn.Game() - game.comment = "foo [%bar] baz" + game.comment = ["foo [%bar] baz"] self.assertTrue(game.clock() is None) clock = 12345 game.set_clock(clock) - self.assertEqual(game.comment, "foo [%bar] baz [%clk 3:25:45]") + self.assertEqual(game.comment, ["foo [%bar] baz", "[%clk 3:25:45]"]) self.assertEqual(game.clock(), clock) self.assertTrue(game.eval() is None) game.set_eval(chess.engine.PovScore(chess.engine.Cp(-80), chess.WHITE)) - self.assertEqual(game.comment, "foo [%bar] baz [%clk 3:25:45] [%eval -0.80]") + self.assertEqual(game.comment, ["foo [%bar] baz", "[%clk 3:25:45]", "[%eval -0.80]"]) self.assertEqual(game.eval().white().score(), -80) self.assertEqual(game.eval_depth(), None) game.set_eval(chess.engine.PovScore(chess.engine.Mate(1), chess.WHITE), 5) - self.assertEqual(game.comment, "foo [%bar] baz [%clk 3:25:45] [%eval #1,5]") + self.assertEqual(game.comment, ["foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) self.assertEqual(game.eval().white().mate(), 1) self.assertEqual(game.eval_depth(), 5) self.assertEqual(game.arrows(), []) game.set_arrows([(chess.A1, chess.A1), chess.svg.Arrow(chess.A1, chess.H1, color="red"), chess.svg.Arrow(chess.B1, chess.B8)]) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%eval #1,5]") + self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) arrows = game.arrows() self.assertEqual(len(arrows), 3) self.assertEqual(arrows[0].color, "green") @@ -2850,18 +2850,18 @@ def test_annotations(self): self.assertTrue(game.emt() is None) emt = 321 game.set_emt(emt) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%eval #1,5] [%emt 0:05:21]") + self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]", "[%emt 0:05:21]"]) self.assertEqual(game.emt(), emt) game.set_eval(None) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%emt 0:05:21]") + self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%emt 0:05:21]"]) game.set_emt(None) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45]") + self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]"]) game.set_clock(None) game.set_arrows([]) - self.assertEqual(game.comment, "foo [%bar] baz") + self.assertEqual(game.comment, ["foo [%bar] baz"]) def test_eval(self): game = chess.pgn.Game() @@ -2871,28 +2871,28 @@ def test_eval(self): def test_float_emt(self): game = chess.pgn.Game() - game.comment = "[%emt 0:00:01.234]" + game.comment = ["[%emt 0:00:01.234]"] self.assertEqual(game.emt(), 1.234) game.set_emt(6.54321) - self.assertEqual(game.comment, "[%emt 0:00:06.543]") + self.assertEqual(game.comment, ["[%emt 0:00:06.543]"]) self.assertEqual(game.emt(), 6.543) game.set_emt(-70) - self.assertEqual(game.comment, "[%emt 0:00:00]") # Clamped + self.assertEqual(game.comment, ["[%emt 0:00:00]"]) # Clamped self.assertEqual(game.emt(), 0) def test_float_clk(self): game = chess.pgn.Game() - game.comment = "[%clk 0:00:01.234]" + game.comment = ["[%clk 0:00:01.234]"] self.assertEqual(game.clock(), 1.234) game.set_clock(6.54321) - self.assertEqual(game.comment, "[%clk 0:00:06.543]") + self.assertEqual(game.comment, ["[%clk 0:00:06.543]"]) self.assertEqual(game.clock(), 6.543) game.set_clock(-70) - self.assertEqual(game.comment, "[%clk 0:00:00]") # Clamped + self.assertEqual(game.comment, ["[%clk 0:00:00]"]) # Clamped self.assertEqual(game.clock(), 0) def test_node_turn(self): From 2269d6a05e137dfe42043474fdaca58c2c6b84a3 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 21 Feb 2024 03:25:33 -0800 Subject: [PATCH 143/250] Add test for exporting a move with multiple comments --- test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index d3961cc6b..2008ef49d 100755 --- a/test.py +++ b/test.py @@ -2100,7 +2100,7 @@ def test_exporter(self): e4_c5.comment = ["Sicilian"] e4_d5_exd5 = e4_d5.add_main_variation(e4_d5.board().parse_san("exd5")) - e4_d5_exd5.comment = ["Best"] + e4_d5_exd5.comment = ["Best", "and the end of this example"] # Test string exporter with various options. exporter = chess.pgn.StringExporter(headers=False, comments=False, variations=False) @@ -2125,7 +2125,7 @@ def test_exporter(self): { Test game: } 1. e4 { Scandinavian Defense: } 1... d5 ( { This } 1... h5 $2 { is nonsense } ) ( 1... e5 2. Qf3 $2 ) ( 1... c5 { Sicilian } ) 2. exd5 - { Best } *""") + { Best } { and the end of this example } *""") self.assertEqual(str(exporter), pgn) # Test file exporter. From 05da5981c5494b1c87b214a0fd46dfc4b0f6ac5a Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 21 Feb 2024 03:48:21 -0800 Subject: [PATCH 144/250] Undo member renaming --- chess/pgn.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 65ef0e6d5..f13812bae 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -197,13 +197,13 @@ class GameNode(abc.ABC): variations: List[ChildNode] """A list of child nodes.""" - comments: list[str] + comment: list[str] """ Comments that go behind the move leading to this node. Comments that occur before any moves are assigned to the root node. """ - starting_comments: list[str] + starting_comment: list[str] nags: Set[int] def __init__(self, *, comment: Union[str, list[str]] = "") -> None: From c06030895cbcf49251279724bd19669c6f580349 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 21 Feb 2024 03:48:45 -0800 Subject: [PATCH 145/250] Add test for reading game with mulit-comment moves --- test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test.py b/test.py index 2008ef49d..c912948c4 100755 --- a/test.py +++ b/test.py @@ -2215,6 +2215,14 @@ def test_read_game(self): self.assertEqual(sixth_game.headers["White"], "Deep Blue (Computer)") self.assertEqual(sixth_game.headers["Result"], "1-0") + def test_read_game_with_multicomment_move(self): + pgn = io.StringIO("1. e4 {A common opening} 1... e5 {A common response} {An uncommon comment}") + game = chess.pgn.read_game(pgn) + first_move = game.variation(0) + self.assertEqual(first_move.comment, ["A common opening"]) + second_move = first_move.variation(0) + self.assertEqual(second_move.comment, ["A common response", "An uncommon comment"]) + def test_comment_at_eol(self): pgn = io.StringIO(textwrap.dedent("""\ 1. e4 e5 2. Nf3 Nc6 3. Bc4 Bc5 4. c3 Nf6 5. d3 d6 6. Nbd2 a6 $6 (6... Bb6 $5 { From 8d076cb77600d84f692e19f70abfdf9d04b93498 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 03:43:33 -0800 Subject: [PATCH 146/250] Undo comment change --- chess/pgn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/pgn.py b/chess/pgn.py index f13812bae..513698dff 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -199,7 +199,7 @@ class GameNode(abc.ABC): comment: list[str] """ - Comments that go behind the move leading to this node. Comments + A comment that goes behind the move leading to this node. Comments that occur before any moves are assigned to the root node. """ From 1df1b76fb064765b7e7510fbe6b35c1b27c3dde0 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 03:55:05 -0800 Subject: [PATCH 147/250] Create class to hold multiple comments --- chess/pgn.py | 116 ++++++++++++++++++++++++++++++++++++++++----------- test.py | 18 ++++---- 2 files changed, 100 insertions(+), 34 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 513698dff..763b90f02 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -184,6 +184,70 @@ def __init__(self, node: ChildNode, *, is_variation: bool = False, sidelines: bo self.in_variation = False +class GameNodeComment: + """ + PGN Comment Storage + + A class that can hold one or more comments for a GameNode. + """ + def __init__(self, comment: Union[str, list[str]] = ""): + self.set(comment) + + def set(self, new_comment: Union[str, list[str]]): + """Replace the comment with a new comment or a list of comments.""" + self._comments = new_comment if isinstance(new_comment, list) else [new_comment] if new_comment else [] + + def pgn_format(self) -> str: + """Create a string representation of the comments in PGN format.""" + comments = list(map(lambda s: s.replace("{", ""), self._comments)) + comments = list(map(lambda s: s.replace("}", "").strip(), comments)) + output_comments = GameNodeComment(comments) + output_comments.remove_empty() + return "{ " + output_comments.join(" } { ") + " }" + + def remove_empty(self) -> None: + """Remove empty comments from the comment list.""" + self._comments = list(filter(None, self._comments)) + + def append(self, new_comment: str) -> None: + """Append a new comment to the end of the comment list.""" + self._comments.append(new_comment) + + def extend(self, new_comments: list[str]) -> None: + """Append several new comments to the end of the comment list.""" + self._comments.extend(new_comments) + + def insert(self, index: int, new_comment: str) -> None: + """Insert a new comment before the specified index.""" + self._comments.insert(index, new_comment) + + def join(self, joiner: str) -> str: + """Join all of the comments together with a joiner string between each.""" + return joiner.join(self._comments) + + def __len__(self) -> int: + return len(self._comments) + + def __getitem__(self, index: int) -> str: + return self._comments[index] + + def __setitem__(self, index: int, new_comment: str) -> None: + self._comments[index] = new_comment + + def __add__(self, other: GameNodeComment) -> GameNodeComment: + return GameNodeComment(self._comments + other._comments) + + def __eq__(self, other: object) -> bool: + if isinstance(other, str): + return len(self) == 1 and self[0] == other + elif isinstance(other, list): + return self._comments == other + elif isinstance(other, GameNodeComment): + return self._comments == other._comments + else: + return False + + class GameNode(abc.ABC): parent: Optional[GameNode] """The parent node or ``None`` if this is the root node of the game.""" @@ -197,24 +261,24 @@ class GameNode(abc.ABC): variations: List[ChildNode] """A list of child nodes.""" - comment: list[str] + comment: GameNodeComment """ A comment that goes behind the move leading to this node. Comments that occur before any moves are assigned to the root node. """ - starting_comment: list[str] + starting_comment: GameNodeComment nags: Set[int] def __init__(self, *, comment: Union[str, list[str]] = "") -> None: self.parent = None self.move = None self.variations = [] - self.comment = comment if isinstance(comment, list) else [comment] if comment else [] + self.comment = GameNodeComment(comment) # Deprecated: These should be properties of ChildNode, but need to # remain here for backwards compatibility. - self.starting_comment: list[str] = [] + self.starting_comment = GameNodeComment() self.nags = set() @abc.abstractmethod @@ -436,7 +500,7 @@ def add_line(self, moves: Iterable[chess.Move], *, comment: Union[str, list[str] else: node.comment.extend(comment) else: - node.comment = comment if isinstance(comment, list) else [comment] if comment else [] + node.comment.set(comment) node.nags.update(nags) @@ -449,7 +513,7 @@ def eval(self) -> Optional[chess.engine.PovScore]: Complexity is `O(n)`. """ - match = EVAL_REGEX.search(" ".join(self.comment)) + match = EVAL_REGEX.search(self.comment.join(" ")) if not match: return None @@ -475,7 +539,7 @@ def eval_depth(self) -> Optional[int]: Complexity is `O(1)`. """ - match = EVAL_REGEX.search(" ".join(self.comment)) + match = EVAL_REGEX.search(self.comment.join(" ")) return int(match.group("depth")) if match and match.group("depth") else None def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] = None) -> None: @@ -498,7 +562,7 @@ def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] if found: break - self.comment = list(filter(None, self.comment)) + self.comment.remove_empty() if not found and eval: self.comment.append(eval) @@ -511,7 +575,7 @@ def arrows(self) -> List[chess.svg.Arrow]: Returns a list of :class:`arrows `. """ arrows = [] - for match in ARROWS_REGEX.finditer(" ".join(self.comment)): + for match in ARROWS_REGEX.finditer(self.comment.join(" ")): for group in match.group("arrows").split(","): arrows.append(chess.svg.Arrow.from_pgn(group)) @@ -536,7 +600,7 @@ def set_arrows(self, arrows: Iterable[Union[chess.svg.Arrow, Tuple[Square, Squar for index in range(len(self.comment)): self.comment[index] = ARROWS_REGEX.sub(_condense_affix(""), self.comment[index]) - self.comment = list(filter(None, self.comment)) + self.comment.remove_empty() prefix = "" if csl: @@ -555,7 +619,7 @@ def clock(self) -> Optional[float]: Returns the player's remaining time to the next time control after this move, in seconds. """ - match = CLOCK_REGEX.search(" ".join(self.comment)) + match = CLOCK_REGEX.search(self.comment.join(" ")) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -580,7 +644,7 @@ def set_clock(self, seconds: Optional[float]) -> None: if found: break - self.comment = list(filter(None, self.comment)) + self.comment.remove_empty() if not found and clk: self.comment.append(clk) @@ -593,7 +657,7 @@ def emt(self) -> Optional[float]: Returns the player's elapsed move time use for the comment of this move, in seconds. """ - match = EMT_REGEX.search(" ".join(self.comment)) + match = EMT_REGEX.search(self.comment.join(" ")) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -618,7 +682,7 @@ def set_emt(self, seconds: Optional[float]) -> None: if found: break - self.comment = list(filter(None, self.comment)) + self.comment.remove_empty() if not found and emt: self.comment.append(emt) @@ -677,7 +741,7 @@ class ChildNode(GameNode): move: chess.Move """The move leading to this node.""" - starting_comment: list[str] + starting_comment: GameNodeComment """ A comment for the start of a variation. Only nodes that actually start a variation (:func:`~chess.pgn.GameNode.starts_variation()` @@ -698,7 +762,7 @@ def __init__(self, parent: GameNode, move: chess.Move, *, comment: Union[str, li self.parent.variations.append(self) self.nags.update(nags) - self.starting_comment = starting_comment if isinstance(starting_comment, list) else [starting_comment] if starting_comment else [] + self.starting_comment = GameNodeComment(starting_comment) def board(self) -> chess.Board: stack: List[chess.Move] = [] @@ -1150,7 +1214,7 @@ def visit_board(self, board: chess.Board) -> None: """ pass - def visit_comment(self, comment: list[str]) -> None: + def visit_comment(self, comment: GameNodeComment) -> None: """Called for each comment.""" pass @@ -1204,7 +1268,7 @@ def begin_game(self) -> None: self.game: GameT = self.Game() self.variation_stack: List[GameNode] = [self.game] - self.starting_comment: list[str] = [] + self.starting_comment = GameNodeComment() self.in_variation = False def begin_headers(self) -> Headers: @@ -1229,22 +1293,24 @@ def visit_result(self, result: str) -> None: if self.game.headers.get("Result", "*") == "*": self.game.headers["Result"] = result - def visit_comment(self, comment: list[str]) -> None: + def visit_comment(self, comment: GameNodeComment) -> None: if self.in_variation or (self.variation_stack[-1].parent is None and self.variation_stack[-1].is_end()): # Add as a comment for the current node if in the middle of # a variation. Add as a comment for the game if the comment # starts before any move. new_comment = self.variation_stack[-1].comment + comment - self.variation_stack[-1].comment = list(filter(None, new_comment)) + new_comment.remove_empty() + self.variation_stack[-1].comment = new_comment else: # Otherwise, it is a starting comment. new_comment = self.starting_comment + comment - self.starting_comment = list(filter(None, new_comment)) + new_comment.remove_empty() + self.starting_comment = new_comment def visit_move(self, board: chess.Board, move: chess.Move) -> None: self.variation_stack[-1] = self.variation_stack[-1].add_variation(move) self.variation_stack[-1].starting_comment = self.starting_comment - self.starting_comment = [] + self.starting_comment = GameNodeComment() self.in_variation = True def handle_error(self, error: Exception) -> None: @@ -1412,9 +1478,9 @@ def end_variation(self) -> None: self.write_token(") ") self.force_movenumber = True - def visit_comment(self, comment: list[str]) -> None: + def visit_comment(self, comment: GameNodeComment) -> None: if self.comments and (self.variations or not self.variation_depth): - self.write_token(" ".join("{ " + single_comment.replace("}", "").strip() + " }" for single_comment in comment) + " ") + self.write_token(comment.pgn_format() + " ") self.force_movenumber = True def visit_nag(self, nag: int) -> None: @@ -1709,7 +1775,7 @@ def read_game(handle: TextIO, *, Visitor: Any = GameBuilder) -> Any: line = line[close_index + 1:] if not skip_variation_depth: - visitor.visit_comment(["".join(comment_lines)]) + visitor.visit_comment(GameNodeComment("".join(comment_lines))) # Continue with the current line. fresh_line = False diff --git a/test.py b/test.py index c912948c4..8750031ca 100755 --- a/test.py +++ b/test.py @@ -2078,29 +2078,29 @@ class PgnTestCase(unittest.TestCase): def test_exporter(self): game = chess.pgn.Game() - game.comment = ["Test game:"] + game.comment.set("Test game:") game.headers["Result"] = "*" game.headers["VeryLongHeader"] = "This is a very long header, much wider than the 80 columns that PGNs are formatted with by default" e4 = game.add_variation(game.board().parse_san("e4")) - e4.comment = ["Scandinavian Defense:"] + e4.comment.set("Scandinavian Defense:") e4_d5 = e4.add_variation(e4.board().parse_san("d5")) e4_h5 = e4.add_variation(e4.board().parse_san("h5")) e4_h5.nags.add(chess.pgn.NAG_MISTAKE) - e4_h5.starting_comment = ["This"] - e4_h5.comment = ["is nonsense"] + e4_h5.starting_comment.set("This") + e4_h5.comment.set("is nonsense") e4_e5 = e4.add_variation(e4.board().parse_san("e5")) e4_e5_Qf3 = e4_e5.add_variation(e4_e5.board().parse_san("Qf3")) e4_e5_Qf3.nags.add(chess.pgn.NAG_MISTAKE) e4_c5 = e4.add_variation(e4.board().parse_san("c5")) - e4_c5.comment = ["Sicilian"] + e4_c5.comment.set("Sicilian") e4_d5_exd5 = e4_d5.add_main_variation(e4_d5.board().parse_san("exd5")) - e4_d5_exd5.comment = ["Best", "and the end of this example"] + e4_d5_exd5.comment.set(["Best", "and the end of this example"]) # Test string exporter with various options. exporter = chess.pgn.StringExporter(headers=False, comments=False, variations=False) @@ -2828,7 +2828,7 @@ def test_recursion(self): def test_annotations(self): game = chess.pgn.Game() - game.comment = ["foo [%bar] baz"] + game.comment = chess.pgn.GameNodeComment("foo [%bar] baz") self.assertTrue(game.clock() is None) clock = 12345 @@ -2879,7 +2879,7 @@ def test_eval(self): def test_float_emt(self): game = chess.pgn.Game() - game.comment = ["[%emt 0:00:01.234]"] + game.comment = chess.pgn.GameNodeComment("[%emt 0:00:01.234]") self.assertEqual(game.emt(), 1.234) game.set_emt(6.54321) @@ -2892,7 +2892,7 @@ def test_float_emt(self): def test_float_clk(self): game = chess.pgn.Game() - game.comment = ["[%clk 0:00:01.234]"] + game.comment.set("[%clk 0:00:01.234]") self.assertEqual(game.clock(), 1.234) game.set_clock(6.54321) From 829a3bf6ded7f8d738655ee924df90812b8af0c2 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 04:01:57 -0800 Subject: [PATCH 148/250] Empty GameNodeComments equal empty strings --- chess/pgn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/pgn.py b/chess/pgn.py index 763b90f02..058c932a8 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -239,7 +239,7 @@ def __add__(self, other: GameNodeComment) -> GameNodeComment: def __eq__(self, other: object) -> bool: if isinstance(other, str): - return len(self) == 1 and self[0] == other + return (len(self) == 1 and self[0] == other) or (not self and not other) elif isinstance(other, list): return self._comments == other elif isinstance(other, GameNodeComment): From 7e0081e6d5b5f1188224a02ab9d78f0fe6b5b80d Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 04:02:15 -0800 Subject: [PATCH 149/250] Revert unnecessary test changes --- test.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test.py b/test.py index 8750031ca..f6d30a4d1 100755 --- a/test.py +++ b/test.py @@ -2219,7 +2219,7 @@ def test_read_game_with_multicomment_move(self): pgn = io.StringIO("1. e4 {A common opening} 1... e5 {A common response} {An uncommon comment}") game = chess.pgn.read_game(pgn) first_move = game.variation(0) - self.assertEqual(first_move.comment, ["A common opening"]) + self.assertEqual(first_move.comment, "A common opening") second_move = first_move.variation(0) self.assertEqual(second_move.comment, ["A common response", "An uncommon comment"]) @@ -2237,7 +2237,7 @@ def test_comment_at_eol(self): # Make sure the comment for the second variation is there. self.assertIn(5, node[1].nags) - self.assertEqual(node[1].comment, ["\n/\\ Ne7, c6"]) + self.assertEqual(node[1].comment, "\n/\\ Ne7, c6") def test_promotion_without_equals(self): # Example game from https://github.com/rozim/ChessData as originally @@ -2325,12 +2325,12 @@ def test_variation_stack(self): def test_game_starting_comment(self): pgn = io.StringIO("{ Game starting comment } 1. d3") game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, ["Game starting comment"]) + self.assertEqual(game.comment, "Game starting comment") self.assertEqual(game[0].san(), "d3") pgn = io.StringIO("{ Empty game, but has a comment }") game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, ["Empty game, but has a comment"]) + self.assertEqual(game.comment, "Empty game, but has a comment") def test_game_starting_variation(self): pgn = io.StringIO(textwrap.dedent("""\ @@ -2338,7 +2338,7 @@ def test_game_starting_variation(self): """)) game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, ["Start of game"]) + self.assertEqual(game.comment, "Start of game") node = game[0] self.assertEqual(node.move, chess.Move.from_uci("e2e4")) @@ -2348,7 +2348,7 @@ def test_game_starting_variation(self): node = game[1] self.assertEqual(node.move, chess.Move.from_uci("d2d4")) self.assertFalse(node.comment) - self.assertEqual(node.starting_comment, ["Start of variation"]) + self.assertEqual(node.starting_comment, "Start of variation") def test_annotation_symbols(self): pgn = io.StringIO("1. b4?! g6 2. Bb2 Nc6? 3. Bxh8!!") @@ -2693,12 +2693,12 @@ def test_add_line(self): tail = game.add_line(moves, starting_comment="start", comment="end", nags=(17, 42)) self.assertEqual(tail.parent.move, chess.Move.from_uci("g1f3")) - self.assertEqual(tail.parent.starting_comment, ["start"]) - self.assertEqual(tail.parent.comment, []) + self.assertEqual(tail.parent.starting_comment, "start") + self.assertEqual(tail.parent.comment, "") self.assertEqual(len(tail.parent.nags), 0) self.assertEqual(tail.move, chess.Move.from_uci("d7d5")) - self.assertEqual(tail.comment, ["end"]) + self.assertEqual(tail.comment, "end") self.assertIn(42, tail.nags) def test_mainline(self): @@ -2828,7 +2828,7 @@ def test_recursion(self): def test_annotations(self): game = chess.pgn.Game() - game.comment = chess.pgn.GameNodeComment("foo [%bar] baz") + game.comment.set("foo [%bar] baz") self.assertTrue(game.clock() is None) clock = 12345 @@ -2869,7 +2869,7 @@ def test_annotations(self): game.set_clock(None) game.set_arrows([]) - self.assertEqual(game.comment, ["foo [%bar] baz"]) + self.assertEqual(game.comment, "foo [%bar] baz") def test_eval(self): game = chess.pgn.Game() @@ -2879,15 +2879,15 @@ def test_eval(self): def test_float_emt(self): game = chess.pgn.Game() - game.comment = chess.pgn.GameNodeComment("[%emt 0:00:01.234]") + game.comment.set("[%emt 0:00:01.234]") self.assertEqual(game.emt(), 1.234) game.set_emt(6.54321) - self.assertEqual(game.comment, ["[%emt 0:00:06.543]"]) + self.assertEqual(game.comment, "[%emt 0:00:06.543]") self.assertEqual(game.emt(), 6.543) game.set_emt(-70) - self.assertEqual(game.comment, ["[%emt 0:00:00]"]) # Clamped + self.assertEqual(game.comment, "[%emt 0:00:00]") # Clamped self.assertEqual(game.emt(), 0) def test_float_clk(self): @@ -2896,11 +2896,11 @@ def test_float_clk(self): self.assertEqual(game.clock(), 1.234) game.set_clock(6.54321) - self.assertEqual(game.comment, ["[%clk 0:00:06.543]"]) + self.assertEqual(game.comment, "[%clk 0:00:06.543]") self.assertEqual(game.clock(), 6.543) game.set_clock(-70) - self.assertEqual(game.comment, ["[%clk 0:00:00]"]) # Clamped + self.assertEqual(game.comment, "[%clk 0:00:00]") # Clamped self.assertEqual(game.clock(), 0) def test_node_turn(self): From b524c3a130c8a535b060af7e73e82339c97617eb Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 04:24:26 -0800 Subject: [PATCH 150/250] Combine append() and extend() methods --- chess/pgn.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 058c932a8..a44aea6fb 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -209,13 +209,13 @@ def remove_empty(self) -> None: """Remove empty comments from the comment list.""" self._comments = list(filter(None, self._comments)) - def append(self, new_comment: str) -> None: - """Append a new comment to the end of the comment list.""" - self._comments.append(new_comment) - - def extend(self, new_comments: list[str]) -> None: - """Append several new comments to the end of the comment list.""" - self._comments.extend(new_comments) + def append(self, new_comment: Union[str, list[str]]) -> None: + """Append one or more new comments to the end of the comment list.""" + if new_comment: + if isinstance(new_comment, str): + self._comments.append(new_comment) + else: + self._comments.extend(new_comment) def insert(self, index: int, new_comment: str) -> None: """Insert a new comment before the specified index.""" @@ -494,14 +494,7 @@ def add_line(self, moves: Iterable[chess.Move], *, comment: Union[str, list[str] starting_comment = "" # Merge comment and NAGs. - if node.comment: - if isinstance(comment, str): - node.comment.append(comment) - else: - node.comment.extend(comment) - else: - node.comment.set(comment) - + node.comment.append(comment) node.nags.update(nags) return node From 9123ebd98765ccda2b81b21118d0a7e007937d10 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 04:30:00 -0800 Subject: [PATCH 151/250] Add missing return type annotation --- chess/pgn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/pgn.py b/chess/pgn.py index a44aea6fb..6fc34133c 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -193,7 +193,7 @@ class GameNodeComment: def __init__(self, comment: Union[str, list[str]] = ""): self.set(comment) - def set(self, new_comment: Union[str, list[str]]): + def set(self, new_comment: Union[str, list[str]]) -> None: """Replace the comment with a new comment or a list of comments.""" self._comments = new_comment if isinstance(new_comment, list) else [new_comment] if new_comment else [] From 4e084cc1d652fcf4070dd8eee0a5c561534631d5 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 20:56:04 -0800 Subject: [PATCH 152/250] Remove unneeded GameNodeComment instance --- chess/pgn.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 6fc34133c..78c238287 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -201,9 +201,8 @@ def pgn_format(self) -> str: """Create a string representation of the comments in PGN format.""" comments = list(map(lambda s: s.replace("{", ""), self._comments)) comments = list(map(lambda s: s.replace("}", "").strip(), comments)) - output_comments = GameNodeComment(comments) - output_comments.remove_empty() - return "{ " + output_comments.join(" } { ") + " }" + comments = list(filter(None, comments)) + return "{ " + " } { ".join(comments) + " }" def remove_empty(self) -> None: """Remove empty comments from the comment list.""" From 91801c873b58d20a48d533027d4f940907a4a3ac Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 21:37:36 -0800 Subject: [PATCH 153/250] Use @property to make changes backwards compatible --- chess/pgn.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ test.py | 18 +++++++++--------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 78c238287..5cc70747a 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -233,8 +233,13 @@ def __getitem__(self, index: int) -> str: def __setitem__(self, index: int, new_comment: str) -> None: self._comments[index] = new_comment - def __add__(self, other: GameNodeComment) -> GameNodeComment: - return GameNodeComment(self._comments + other._comments) + def __add__(self, other: Union[str, list[str], GameNodeComment]) -> GameNodeComment: + if not isinstance(other, GameNodeComment): + new_node_comment = GameNodeComment(self._comments) + new_node_comment.append(other) + return new_node_comment + else: + return GameNodeComment(self._comments + other._comments) def __eq__(self, other: object) -> bool: if isinstance(other, str): @@ -260,13 +265,37 @@ class GameNode(abc.ABC): variations: List[ChildNode] """A list of child nodes.""" - comment: GameNodeComment + _comment: GameNodeComment """ A comment that goes behind the move leading to this node. Comments that occur before any moves are assigned to the root node. """ - starting_comment: GameNodeComment + @property + def comment(self) -> GameNodeComment: + return self._comment + + @comment.setter + def comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: + if isinstance(new_comment, GameNodeComment): + self._comment = new_comment + else: + self._comment = GameNodeComment(new_comment) + + + _starting_comment: GameNodeComment + + @property + def starting_comment(self) -> GameNodeComment: + return self._starting_comment + + @starting_comment.setter + def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: + if isinstance(new_comment, GameNodeComment): + self._starting_comment = new_comment + else: + self._starting_comment = GameNodeComment(new_comment) + nags: Set[int] def __init__(self, *, comment: Union[str, list[str]] = "") -> None: @@ -733,7 +762,7 @@ class ChildNode(GameNode): move: chess.Move """The move leading to this node.""" - starting_comment: GameNodeComment + _starting_comment: GameNodeComment """ A comment for the start of a variation. Only nodes that actually start a variation (:func:`~chess.pgn.GameNode.starts_variation()` @@ -741,6 +770,17 @@ class ChildNode(GameNode): a starting comment. """ + @property + def starting_comment(self) -> GameNodeComment: + return self._starting_comment + + @starting_comment.setter + def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: + if isinstance(new_comment, GameNodeComment): + self._starting_comment = new_comment + else: + self._starting_comment = GameNodeComment(new_comment) + nags: Set[int] """ A set of NAGs as integers. NAGs always go behind a move, so the root @@ -1767,7 +1807,7 @@ def read_game(handle: TextIO, *, Visitor: Any = GameBuilder) -> Any: line = line[close_index + 1:] if not skip_variation_depth: - visitor.visit_comment(GameNodeComment("".join(comment_lines))) + visitor.visit_comment("".join(comment_lines)) # Continue with the current line. fresh_line = False diff --git a/test.py b/test.py index f6d30a4d1..91e54e5d5 100755 --- a/test.py +++ b/test.py @@ -2078,29 +2078,29 @@ class PgnTestCase(unittest.TestCase): def test_exporter(self): game = chess.pgn.Game() - game.comment.set("Test game:") + game.comment = "Test game:" game.headers["Result"] = "*" game.headers["VeryLongHeader"] = "This is a very long header, much wider than the 80 columns that PGNs are formatted with by default" e4 = game.add_variation(game.board().parse_san("e4")) - e4.comment.set("Scandinavian Defense:") + e4.comment = "Scandinavian Defense:" e4_d5 = e4.add_variation(e4.board().parse_san("d5")) e4_h5 = e4.add_variation(e4.board().parse_san("h5")) e4_h5.nags.add(chess.pgn.NAG_MISTAKE) - e4_h5.starting_comment.set("This") - e4_h5.comment.set("is nonsense") + e4_h5.starting_comment = "This" + e4_h5.comment = "is nonsense" e4_e5 = e4.add_variation(e4.board().parse_san("e5")) e4_e5_Qf3 = e4_e5.add_variation(e4_e5.board().parse_san("Qf3")) e4_e5_Qf3.nags.add(chess.pgn.NAG_MISTAKE) e4_c5 = e4.add_variation(e4.board().parse_san("c5")) - e4_c5.comment.set("Sicilian") + e4_c5.comment = "Sicilian" e4_d5_exd5 = e4_d5.add_main_variation(e4_d5.board().parse_san("exd5")) - e4_d5_exd5.comment.set(["Best", "and the end of this example"]) + e4_d5_exd5.comment = ["Best", "and the end of this example"] # Test string exporter with various options. exporter = chess.pgn.StringExporter(headers=False, comments=False, variations=False) @@ -2828,7 +2828,7 @@ def test_recursion(self): def test_annotations(self): game = chess.pgn.Game() - game.comment.set("foo [%bar] baz") + game.comment = "foo [%bar] baz" self.assertTrue(game.clock() is None) clock = 12345 @@ -2879,7 +2879,7 @@ def test_eval(self): def test_float_emt(self): game = chess.pgn.Game() - game.comment.set("[%emt 0:00:01.234]") + game.comment = "[%emt 0:00:01.234]" self.assertEqual(game.emt(), 1.234) game.set_emt(6.54321) @@ -2892,7 +2892,7 @@ def test_float_emt(self): def test_float_clk(self): game = chess.pgn.Game() - game.comment.set("[%clk 0:00:01.234]") + game.comment = "[%clk 0:00:01.234]" self.assertEqual(game.clock(), 1.234) game.set_clock(6.54321) From 54e044ac6fc2e9288453a72b3a8db435d3380f2b Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 21:50:47 -0800 Subject: [PATCH 154/250] Positive branch first --- chess/pgn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 5cc70747a..a9910f45b 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -234,12 +234,12 @@ def __setitem__(self, index: int, new_comment: str) -> None: self._comments[index] = new_comment def __add__(self, other: Union[str, list[str], GameNodeComment]) -> GameNodeComment: - if not isinstance(other, GameNodeComment): - new_node_comment = GameNodeComment(self._comments) + if isinstance(other, GameNodeComment): + return GameNodeComment(self._comments + other._comments) + else: + new_node_comment = GameNodeComment(self._comments.copy()) new_node_comment.append(other) return new_node_comment - else: - return GameNodeComment(self._comments + other._comments) def __eq__(self, other: object) -> bool: if isinstance(other, str): From aa47f1e7de3a36ff117b6b2ac9c3ef0b23bef3b8 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 22:11:05 -0800 Subject: [PATCH 155/250] Add display methods to GameNodeComment --- chess/pgn.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chess/pgn.py b/chess/pgn.py index a9910f45b..7695a1c68 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -251,6 +251,12 @@ def __eq__(self, other: object) -> bool: else: return False + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self._comments})" + + def __str__(self) -> str: + return self.pgn_format() + class GameNode(abc.ABC): parent: Optional[GameNode] From f1a56125104ca3c80a9c615c949d18401b465948 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Thu, 22 Feb 2024 22:57:05 -0800 Subject: [PATCH 156/250] Create method for deleting individual comments --- chess/pgn.py | 4 ++++ test.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/chess/pgn.py b/chess/pgn.py index 7695a1c68..fd3096013 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -220,6 +220,10 @@ def insert(self, index: int, new_comment: str) -> None: """Insert a new comment before the specified index.""" self._comments.insert(index, new_comment) + def pop(self, index: int = -1) -> None: + """Delete comment at the given index (default is the last comment).""" + self._comments.pop(index) + def join(self, joiner: str) -> str: """Join all of the comments together with a joiner string between each.""" return joiner.join(self._comments) diff --git a/test.py b/test.py index 91e54e5d5..cbc41d6dd 100755 --- a/test.py +++ b/test.py @@ -2222,6 +2222,14 @@ def test_read_game_with_multicomment_move(self): self.assertEqual(first_move.comment, "A common opening") second_move = first_move.variation(0) self.assertEqual(second_move.comment, ["A common response", "An uncommon comment"]) + second_move.comment.pop() + self.assertEqual(second_move.comment, ["A common response"]) + self.assertEqual(second_move.comment, "A common response") + second_move.comment.append("A replaced comment") + self.assertEqual(second_move.comment, ["A common response", "A replaced comment"]) + second_move.comment.pop(0) + self.assertEqual(second_move.comment, ["A replaced comment"]) + self.assertEqual(second_move.comment, "A replaced comment") def test_comment_at_eol(self): pgn = io.StringIO(textwrap.dedent("""\ From 8e91525e47593932911951919a6855f2ea2aa170 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 24 Feb 2024 20:20:38 +0100 Subject: [PATCH 157/250] Add sf16.1 WDL model --- chess/engine.py | 17 +++++++++++++++-- test.py | 3 ++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index b1d3896ab..b72bf5907 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -24,7 +24,7 @@ from types import TracebackType from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypedDict, TypeVar, Union -WdlModel = Literal["sf", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] +WdlModel = Literal["sf", "sf16.1", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] T = TypeVar("T") @@ -516,6 +516,16 @@ def __ge__(self, other: object) -> bool: else: return NotImplemented +def _sf16_1_wins(cp: int, *, ply=int) -> int: + # https://github.com/official-stockfish/Stockfish/blob/sf_16.1/src/uci.cpp#L48 + NormalizeToPawnValue = 356 + # https://github.com/official-stockfish/Stockfish/blob/sf_16.1/src/uci.cpp#L383-L384 + m = min(120, max(8, ply / 2 + 1)) / 32 + a = (((-1.06249702 * m + 7.42016937) * m + 0.89425629) * m) + 348.60356174 + b = (((-5.33122190 * m + 39.57831533) * m + -90.84473771) * m) + 123.40620748 + x = min(4000, max(cp * NormalizeToPawnValue / 100, -4000)) + return int(0.5 + 1000 / (1 + math.exp((a - x) / b))) + def _sf16_wins(cp: int, *, ply: int) -> int: # https://github.com/official-stockfish/Stockfish/blob/sf_16/src/uci.h#L38 NormalizeToPawnValue = 328 @@ -594,9 +604,12 @@ def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl: elif model == "sf15.1": wins = _sf15_1_wins(self.cp, ply=ply) losses = _sf15_1_wins(-self.cp, ply=ply) - else: + elif model == "sf16": wins = _sf16_wins(self.cp, ply=ply) losses = _sf16_wins(-self.cp, ply=ply) + else: + wins = _sf16_1_wins(self.cp, ply=ply) + losses = _sf16_1_wins(-self.cp, ply=ply) draws = 1000 - wins - losses return Wdl(wins, draws, losses) diff --git a/test.py b/test.py index e1d0d50c5..8dbc95a25 100755 --- a/test.py +++ b/test.py @@ -2995,7 +2995,7 @@ def test_score_ordering(self): self.assertEqual(i >= j, a >= b) self.assertEqual(i < j, a.score(mate_score=100000) < b.score(mate_score=100000)) - for model in ["sf12", "sf14", "sf15", "sf15.1", "sf16"]: + for model in ["sf12", "sf14", "sf15", "sf15.1", "sf16", "sf16.1"]: self.assertTrue(not (i < j) or a.wdl(model=model).expectation() <= b.wdl(model=model).expectation()) self.assertTrue(not (i < j) or a.wdl(model=model).winning_chance() <= b.wdl(model=model).winning_chance()) self.assertTrue(not (i < j) or a.wdl(model=model).losing_chance() >= b.wdl(model=model).losing_chance()) @@ -3035,6 +3035,7 @@ def test_wdl_model(self): self.assertEqual(chess.engine.Cp(40).wdl(model="sf15", ply=25), chess.engine.Wdl(58, 937, 5)) self.assertEqual(chess.engine.Cp(100).wdl(model="sf15.1", ply=64), chess.engine.Wdl(497, 503, 0)) self.assertEqual(chess.engine.Cp(-52).wdl(model="sf16", ply=63), chess.engine.Wdl(0, 932, 68)) + self.assertEqual(chess.engine.Cp(51).wdl(model="sf16.1", ply=158), chess.engine.Wdl(36, 964, 0)) @catchAndSkip(FileNotFoundError, "need stockfish") def test_sf_forced_mates(self): From 315052c0105ea1e0d0b4e1cbee70577fd9349f2d Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 24 Feb 2024 20:25:56 +0100 Subject: [PATCH 158/250] Fix argument syntax --- chess/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index b72bf5907..c2b470dd5 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -516,7 +516,7 @@ def __ge__(self, other: object) -> bool: else: return NotImplemented -def _sf16_1_wins(cp: int, *, ply=int) -> int: +def _sf16_1_wins(cp: int, *, ply: int) -> int: # https://github.com/official-stockfish/Stockfish/blob/sf_16.1/src/uci.cpp#L48 NormalizeToPawnValue = 356 # https://github.com/official-stockfish/Stockfish/blob/sf_16.1/src/uci.cpp#L383-L384 From 8756e7878b2076fe9a7fe574086e43be58d4e7a2 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 28 Feb 2024 01:05:43 -0800 Subject: [PATCH 159/250] Test that GameNodeComment is iterable --- test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test.py b/test.py index cbc41d6dd..ee770de0f 100755 --- a/test.py +++ b/test.py @@ -2226,7 +2226,11 @@ def test_read_game_with_multicomment_move(self): self.assertEqual(second_move.comment, ["A common response"]) self.assertEqual(second_move.comment, "A common response") second_move.comment.append("A replaced comment") - self.assertEqual(second_move.comment, ["A common response", "A replaced comment"]) + multiple_comments = ["A common response", "A replaced comment"] + self.assertEqual(second_move.comment, multiple_comments) + for move_comment, test_comment in zip(second_move.comment, multiple_comments): + self.assertEqual(move_comment, test_comment) + self.assertEqual(list(second_move.comment), multiple_comments) second_move.comment.pop(0) self.assertEqual(second_move.comment, ["A replaced comment"]) self.assertEqual(second_move.comment, "A replaced comment") From 603c9755e23093ddf985a603fa19f6b24878cad0 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 28 Feb 2024 01:20:01 -0800 Subject: [PATCH 160/250] Make pgn_format() code easier to read --- chess/pgn.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index fd3096013..2d7f31096 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -199,10 +199,9 @@ def set(self, new_comment: Union[str, list[str]]) -> None: def pgn_format(self) -> str: """Create a string representation of the comments in PGN format.""" - comments = list(map(lambda s: s.replace("{", ""), self._comments)) - comments = list(map(lambda s: s.replace("}", "").strip(), comments)) - comments = list(filter(None, comments)) - return "{ " + " } { ".join(comments) + " }" + comments = map(lambda s: s.replace("{", ""), self._comments) + comments = map(lambda s: s.replace("}", "").strip(), comments) + return " ".join(f"{{ {comment} }}" for comment in comments if comment) def remove_empty(self) -> None: """Remove empty comments from the comment list.""" From cce50dcacd0774d6a6595de1ce65b5f0dd7b5101 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 28 Feb 2024 01:54:19 -0800 Subject: [PATCH 161/250] Use built-in join() --- chess/pgn.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 2d7f31096..0e0345a92 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -223,10 +223,6 @@ def pop(self, index: int = -1) -> None: """Delete comment at the given index (default is the last comment).""" self._comments.pop(index) - def join(self, joiner: str) -> str: - """Join all of the comments together with a joiner string between each.""" - return joiner.join(self._comments) - def __len__(self) -> int: return len(self._comments) @@ -236,6 +232,9 @@ def __getitem__(self, index: int) -> str: def __setitem__(self, index: int, new_comment: str) -> None: self._comments[index] = new_comment + def __iter__(self) -> Iterator[str]: + return iter(self._comments) + def __add__(self, other: Union[str, list[str], GameNodeComment]) -> GameNodeComment: if isinstance(other, GameNodeComment): return GameNodeComment(self._comments + other._comments) @@ -543,7 +542,7 @@ def eval(self) -> Optional[chess.engine.PovScore]: Complexity is `O(n)`. """ - match = EVAL_REGEX.search(self.comment.join(" ")) + match = EVAL_REGEX.search(" ".join(self.comment)) if not match: return None @@ -569,7 +568,7 @@ def eval_depth(self) -> Optional[int]: Complexity is `O(1)`. """ - match = EVAL_REGEX.search(self.comment.join(" ")) + match = EVAL_REGEX.search(" ".join(self.comment)) return int(match.group("depth")) if match and match.group("depth") else None def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] = None) -> None: @@ -605,7 +604,7 @@ def arrows(self) -> List[chess.svg.Arrow]: Returns a list of :class:`arrows `. """ arrows = [] - for match in ARROWS_REGEX.finditer(self.comment.join(" ")): + for match in ARROWS_REGEX.finditer(" ".join(self.comment)): for group in match.group("arrows").split(","): arrows.append(chess.svg.Arrow.from_pgn(group)) @@ -649,7 +648,7 @@ def clock(self) -> Optional[float]: Returns the player's remaining time to the next time control after this move, in seconds. """ - match = CLOCK_REGEX.search(self.comment.join(" ")) + match = CLOCK_REGEX.search(" ".join(self.comment)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -687,7 +686,7 @@ def emt(self) -> Optional[float]: Returns the player's elapsed move time use for the comment of this move, in seconds. """ - match = EMT_REGEX.search(self.comment.join(" ")) + match = EMT_REGEX.search(" ".join(self.comment)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) From 4e695e2bc7c50066c0f84abd4206e61c917b2d03 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 28 Feb 2024 02:04:08 -0800 Subject: [PATCH 162/250] Add docstrings for methods Also, fix spacing. --- chess/pgn.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/chess/pgn.py b/chess/pgn.py index 0e0345a92..36cac2c59 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -190,7 +190,9 @@ class GameNodeComment: A class that can hold one or more comments for a GameNode. """ + def __init__(self, comment: Union[str, list[str]] = ""): + """Create a new comment.""" self.set(comment) def set(self, new_comment: Union[str, list[str]]) -> None: @@ -224,18 +226,23 @@ def pop(self, index: int = -1) -> None: self._comments.pop(index) def __len__(self) -> int: + """Get the number of comments in this node.""" return len(self._comments) def __getitem__(self, index: int) -> str: + """Get the comment at the given index.""" return self._comments[index] def __setitem__(self, index: int, new_comment: str) -> None: + """Change the comment at the given index.""" self._comments[index] = new_comment def __iter__(self) -> Iterator[str]: + """Return an iterator over all comments.""" return iter(self._comments) def __add__(self, other: Union[str, list[str], GameNodeComment]) -> GameNodeComment: + """Create a new comment set by adding two comment sets with +.""" if isinstance(other, GameNodeComment): return GameNodeComment(self._comments + other._comments) else: @@ -244,6 +251,7 @@ def __add__(self, other: Union[str, list[str], GameNodeComment]) -> GameNodeComm return new_node_comment def __eq__(self, other: object) -> bool: + """Check for equality between two comment sets.""" if isinstance(other, str): return (len(self) == 1 and self[0] == other) or (not self and not other) elif isinstance(other, list): @@ -254,9 +262,11 @@ def __eq__(self, other: object) -> bool: return False def __repr__(self) -> str: + """Return a code-like representation of the class.""" return f"{self.__class__.__name__}({self._comments})" def __str__(self) -> str: + """Return a string representation of the comments in PGN format.""" return self.pgn_format() @@ -290,7 +300,6 @@ def comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: else: self._comment = GameNodeComment(new_comment) - _starting_comment: GameNodeComment @property From d1dce61a45ed3784ce867ec0218d6fb3ca47e735 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 18 Apr 2024 15:53:08 +0200 Subject: [PATCH 163/250] Bump Sphinx to 7.3.6 --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index a63c6a7ca..7516f64de 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ -Sphinx==6.1.2 +Sphinx==7.3.6 sphinxcontrib-jquery==4.1 sphinx-rtd-theme==1.3.0 From 4c7a9025e3442fb75a14eae367fd88200e210042 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 18 Apr 2024 17:40:45 +0200 Subject: [PATCH 164/250] Use typing_extensions.TypeAlias (#564) --- chess/__init__.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index a9328a04b..9eeb2c5e2 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -24,15 +24,19 @@ from typing import ClassVar, Callable, Counter, Dict, Generic, Hashable, Iterable, Iterator, List, Literal, Mapping, Optional, SupportsInt, Tuple, Type, TypeVar, Union +if typing.TYPE_CHECKING: + from typing_extensions import TypeAlias + + EnPassantSpec = Literal["legal", "fen", "xfen"] -Color = bool +Color: TypeAlias = bool COLORS = [WHITE, BLACK] = [True, False] ColorName = Literal["white", "black"] COLOR_NAMES: List[ColorName] = ["black", "white"] -PieceType = int +PieceType: TypeAlias = int PIECE_TYPES = [PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING] = range(1, 7) PIECE_SYMBOLS = [None, "p", "n", "b", "r", "q", "k"] PIECE_NAMES = [None, "pawn", "knight", "bishop", "rook", "queen", "king"] @@ -157,7 +161,7 @@ class AmbiguousMoveError(ValueError): """Raised when the attempted move is ambiguous in the current position""" -Square = int +Square: TypeAlias = int SQUARES = [ A1, B1, C1, D1, E1, F1, G1, H1, A2, B2, C2, D2, E2, F2, G2, H2, @@ -233,7 +237,7 @@ def square_mirror(square: Square) -> Square: SQUARES_180 = [square_mirror(sq) for sq in SQUARES] -Bitboard = int +Bitboard: TypeAlias = int BB_EMPTY = 0 BB_ALL = 0xffff_ffff_ffff_ffff @@ -3816,7 +3820,7 @@ def __repr__(self) -> str: return f"" -IntoSquareSet = Union[SupportsInt, Iterable[Square]] +IntoSquareSet: TypeAlias = Union[SupportsInt, Iterable[Square]] class SquareSet: """ From 6af0ff4c8947486e3e3fa8e83ca88815301aaa37 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 18 Apr 2024 17:59:10 +0200 Subject: [PATCH 165/250] Expand core constant definitions More verbose, but better IDE support --- chess/__init__.py | 234 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 175 insertions(+), 59 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 9eeb2c5e2..f9a9ab7f5 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -32,12 +32,20 @@ Color: TypeAlias = bool -COLORS = [WHITE, BLACK] = [True, False] +WHITE: Color = True +BLACK: Color = False +COLORS: List[Color] = [WHITE, BLACK] ColorName = Literal["white", "black"] COLOR_NAMES: List[ColorName] = ["black", "white"] PieceType: TypeAlias = int -PIECE_TYPES = [PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING] = range(1, 7) +PAWN: PieceType = 1 +KNIGHT: PieceType = 2 +BISHOP: PieceType = 3 +ROOK: PieceType = 4 +QUEEN: PieceType = 5 +KING: PieceType = 6 +PIECE_TYPES: List[PieceType] = [PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING] PIECE_SYMBOLS = [None, "p", "n", "b", "r", "q", "k"] PIECE_NAMES = [None, "pawn", "knight", "bishop", "rook", "queen", "king"] @@ -162,16 +170,71 @@ class AmbiguousMoveError(ValueError): Square: TypeAlias = int -SQUARES = [ - A1, B1, C1, D1, E1, F1, G1, H1, - A2, B2, C2, D2, E2, F2, G2, H2, - A3, B3, C3, D3, E3, F3, G3, H3, - A4, B4, C4, D4, E4, F4, G4, H4, - A5, B5, C5, D5, E5, F5, G5, H5, - A6, B6, C6, D6, E6, F6, G6, H6, - A7, B7, C7, D7, E7, F7, G7, H7, - A8, B8, C8, D8, E8, F8, G8, H8, -] = range(64) +A1: Square = 0 +B1: Square = 1 +C1: Square = 2 +D1: Square = 3 +E1: Square = 4 +F1: Square = 5 +G1: Square = 6 +H1: Square = 7 +A2: Square = 8 +B2: Square = 9 +C2: Square = 10 +D2: Square = 11 +E2: Square = 12 +F2: Square = 13 +G2: Square = 14 +H2: Square = 15 +A3: Square = 16 +B3: Square = 17 +C3: Square = 18 +D3: Square = 19 +E3: Square = 20 +F3: Square = 21 +G3: Square = 22 +H3: Square = 23 +A4: Square = 24 +B4: Square = 25 +C4: Square = 26 +D4: Square = 27 +E4: Square = 28 +F4: Square = 29 +G4: Square = 30 +H4: Square = 31 +A5: Square = 32 +B5: Square = 33 +C5: Square = 34 +D5: Square = 35 +E5: Square = 36 +F5: Square = 37 +G5: Square = 38 +H5: Square = 39 +A6: Square = 40 +B6: Square = 41 +C6: Square = 42 +D6: Square = 43 +E6: Square = 44 +F6: Square = 45 +G6: Square = 46 +H6: Square = 47 +A7: Square = 48 +B7: Square = 49 +C7: Square = 50 +D7: Square = 51 +E7: Square = 52 +F7: Square = 53 +G7: Square = 54 +H7: Square = 55 +A8: Square = 56 +B8: Square = 57 +C8: Square = 58 +D8: Square = 59 +E8: Square = 60 +F8: Square = 61 +G8: Square = 62 +H8: Square = 63 +SQUARES: List[Square] = list(range(64)) SQUARE_NAMES = [f + r for r in RANK_NAMES for f in FILE_NAMES] @@ -234,53 +297,106 @@ def square_mirror(square: Square) -> Square: """Mirrors the square vertically.""" return square ^ 0x38 -SQUARES_180 = [square_mirror(sq) for sq in SQUARES] +SQUARES_180: List[Square] = [square_mirror(sq) for sq in SQUARES] Bitboard: TypeAlias = int -BB_EMPTY = 0 -BB_ALL = 0xffff_ffff_ffff_ffff - -BB_SQUARES = [ - BB_A1, BB_B1, BB_C1, BB_D1, BB_E1, BB_F1, BB_G1, BB_H1, - BB_A2, BB_B2, BB_C2, BB_D2, BB_E2, BB_F2, BB_G2, BB_H2, - BB_A3, BB_B3, BB_C3, BB_D3, BB_E3, BB_F3, BB_G3, BB_H3, - BB_A4, BB_B4, BB_C4, BB_D4, BB_E4, BB_F4, BB_G4, BB_H4, - BB_A5, BB_B5, BB_C5, BB_D5, BB_E5, BB_F5, BB_G5, BB_H5, - BB_A6, BB_B6, BB_C6, BB_D6, BB_E6, BB_F6, BB_G6, BB_H6, - BB_A7, BB_B7, BB_C7, BB_D7, BB_E7, BB_F7, BB_G7, BB_H7, - BB_A8, BB_B8, BB_C8, BB_D8, BB_E8, BB_F8, BB_G8, BB_H8, -] = [1 << sq for sq in SQUARES] - -BB_CORNERS = BB_A1 | BB_H1 | BB_A8 | BB_H8 -BB_CENTER = BB_D4 | BB_E4 | BB_D5 | BB_E5 - -BB_LIGHT_SQUARES = 0x55aa_55aa_55aa_55aa -BB_DARK_SQUARES = 0xaa55_aa55_aa55_aa55 - -BB_FILES = [ - BB_FILE_A, - BB_FILE_B, - BB_FILE_C, - BB_FILE_D, - BB_FILE_E, - BB_FILE_F, - BB_FILE_G, - BB_FILE_H, -] = [0x0101_0101_0101_0101 << i for i in range(8)] - -BB_RANKS = [ - BB_RANK_1, - BB_RANK_2, - BB_RANK_3, - BB_RANK_4, - BB_RANK_5, - BB_RANK_6, - BB_RANK_7, - BB_RANK_8, -] = [0xff << (8 * i) for i in range(8)] - -BB_BACKRANKS = BB_RANK_1 | BB_RANK_8 +BB_EMPTY: Bitboard = 0 +BB_ALL: Bitboard = 0xffff_ffff_ffff_ffff + +BB_A1: Bitboard = 1 << A1 +BB_B1: Bitboard = 1 << B1 +BB_C1: Bitboard = 1 << C1 +BB_D1: Bitboard = 1 << D1 +BB_E1: Bitboard = 1 << E1 +BB_F1: Bitboard = 1 << F1 +BB_G1: Bitboard = 1 << G1 +BB_H1: Bitboard = 1 << H1 +BB_A2: Bitboard = 1 << A2 +BB_B2: Bitboard = 1 << B2 +BB_C2: Bitboard = 1 << C2 +BB_D2: Bitboard = 1 << D2 +BB_E2: Bitboard = 1 << E2 +BB_F2: Bitboard = 1 << F2 +BB_G2: Bitboard = 1 << G2 +BB_H2: Bitboard = 1 << H2 +BB_A3: Bitboard = 1 << A3 +BB_B3: Bitboard = 1 << B3 +BB_C3: Bitboard = 1 << C3 +BB_D3: Bitboard = 1 << D3 +BB_E3: Bitboard = 1 << E3 +BB_F3: Bitboard = 1 << F3 +BB_G3: Bitboard = 1 << G3 +BB_H3: Bitboard = 1 << H3 +BB_A4: Bitboard = 1 << A4 +BB_B4: Bitboard = 1 << B4 +BB_C4: Bitboard = 1 << C4 +BB_D4: Bitboard = 1 << D4 +BB_E4: Bitboard = 1 << E4 +BB_F4: Bitboard = 1 << F4 +BB_G4: Bitboard = 1 << G4 +BB_H4: Bitboard = 1 << H4 +BB_A5: Bitboard = 1 << A5 +BB_B5: Bitboard = 1 << B5 +BB_C5: Bitboard = 1 << C5 +BB_D5: Bitboard = 1 << D5 +BB_E5: Bitboard = 1 << E5 +BB_F5: Bitboard = 1 << F5 +BB_G5: Bitboard = 1 << G5 +BB_H5: Bitboard = 1 << H5 +BB_A6: Bitboard = 1 << A6 +BB_B6: Bitboard = 1 << B6 +BB_C6: Bitboard = 1 << C6 +BB_D6: Bitboard = 1 << D6 +BB_E6: Bitboard = 1 << E6 +BB_F6: Bitboard = 1 << F6 +BB_G6: Bitboard = 1 << G6 +BB_H6: Bitboard = 1 << H6 +BB_A7: Bitboard = 1 << A7 +BB_B7: Bitboard = 1 << B7 +BB_C7: Bitboard = 1 << C7 +BB_D7: Bitboard = 1 << D7 +BB_E7: Bitboard = 1 << E7 +BB_F7: Bitboard = 1 << F7 +BB_G7: Bitboard = 1 << G7 +BB_H7: Bitboard = 1 << H7 +BB_A8: Bitboard = 1 << A8 +BB_B8: Bitboard = 1 << B8 +BB_C8: Bitboard = 1 << C8 +BB_D8: Bitboard = 1 << D8 +BB_E8: Bitboard = 1 << E8 +BB_F8: Bitboard = 1 << F8 +BB_G8: Bitboard = 1 << G8 +BB_H8: Bitboard = 1 << H8 +BB_SQUARES: List[Bitboard] = [1 << sq for sq in SQUARES] + +BB_CORNERS: Bitboard = BB_A1 | BB_H1 | BB_A8 | BB_H8 +BB_CENTER: Bitboard = BB_D4 | BB_E4 | BB_D5 | BB_E5 + +BB_LIGHT_SQUARES: Bitboard = 0x55aa_55aa_55aa_55aa +BB_DARK_SQUARES: Bitboard = 0xaa55_aa55_aa55_aa55 + +BB_FILE_A: Bitboard = 0x0101_0101_0101_0101 << 0 +BB_FILE_B: Bitboard = 0x0101_0101_0101_0101 << 1 +BB_FILE_C: Bitboard = 0x0101_0101_0101_0101 << 2 +BB_FILE_D: Bitboard = 0x0101_0101_0101_0101 << 3 +BB_FILE_E: Bitboard = 0x0101_0101_0101_0101 << 4 +BB_FILE_F: Bitboard = 0x0101_0101_0101_0101 << 5 +BB_FILE_G: Bitboard = 0x0101_0101_0101_0101 << 6 +BB_FILE_H: Bitboard = 0x0101_0101_0101_0101 << 7 +BB_FILES: List[Bitboard] = [BB_FILE_A, BB_FILE_B, BB_FILE_C, BB_FILE_D, BB_FILE_E, BB_FILE_F, BB_FILE_G, BB_FILE_H] + +BB_RANK_1: Bitboard = 0xff << (8 * 0) +BB_RANK_2: Bitboard = 0xff << (8 * 1) +BB_RANK_3: Bitboard = 0xff << (8 * 2) +BB_RANK_4: Bitboard = 0xff << (8 * 3) +BB_RANK_5: Bitboard = 0xff << (8 * 4) +BB_RANK_6: Bitboard = 0xff << (8 * 5) +BB_RANK_7: Bitboard = 0xff << (8 * 6) +BB_RANK_8: Bitboard = 0xff << (8 * 7) +BB_RANKS: List[Bitboard] = [BB_RANK_1, BB_RANK_2, BB_RANK_3, BB_RANK_4, BB_RANK_5, BB_RANK_6, BB_RANK_7, BB_RANK_8] + +BB_BACKRANKS: Bitboard = BB_RANK_1 | BB_RANK_8 def lsb(bb: Bitboard) -> int: @@ -397,9 +513,9 @@ def _sliding_attacks(square: Square, occupied: Bitboard, deltas: Iterable[int]) def _step_attacks(square: Square, deltas: Iterable[int]) -> Bitboard: return _sliding_attacks(square, BB_ALL, deltas) -BB_KNIGHT_ATTACKS = [_step_attacks(sq, [17, 15, 10, 6, -17, -15, -10, -6]) for sq in SQUARES] -BB_KING_ATTACKS = [_step_attacks(sq, [9, 8, 7, 1, -9, -8, -7, -1]) for sq in SQUARES] -BB_PAWN_ATTACKS = [[_step_attacks(sq, deltas) for sq in SQUARES] for deltas in [[-7, -9], [7, 9]]] +BB_KNIGHT_ATTACKS: List[Bitboard] = [_step_attacks(sq, [17, 15, 10, 6, -17, -15, -10, -6]) for sq in SQUARES] +BB_KING_ATTACKS: List[Bitboard] = [_step_attacks(sq, [9, 8, 7, 1, -9, -8, -7, -1]) for sq in SQUARES] +BB_PAWN_ATTACKS: List[List[Bitboard]] = [[_step_attacks(sq, deltas) for sq in SQUARES] for deltas in [[-7, -9], [7, 9]]] def _edges(square: Square) -> Bitboard: From 90d81da2416bf8e3f4ffdbdd70e6105fea8607b4 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 20 Apr 2024 21:04:40 -0700 Subject: [PATCH 166/250] Restore previous behavior of GameNode.comment GameNode.comment now returns all comments as a single string with single spaces separating the comments. GameNode.comments (plural) returns all comments as a list of strings. --- chess/pgn.py | 90 +++++++++++++++++++++++++++++++--------------------- test.py | 43 +++++++++++++++---------- 2 files changed, 80 insertions(+), 53 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 36cac2c59..50984a64d 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -290,8 +290,8 @@ class GameNode(abc.ABC): """ @property - def comment(self) -> GameNodeComment: - return self._comment + def comment(self) -> str: + return " ".join(self._comment) @comment.setter def comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: @@ -300,11 +300,19 @@ def comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: else: self._comment = GameNodeComment(new_comment) + @property + def comments(self) -> GameNodeComment: + return self._comment + + @comments.setter + def comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: + self.comment = new_comment + _starting_comment: GameNodeComment @property - def starting_comment(self) -> GameNodeComment: - return self._starting_comment + def starting_comment(self) -> str: + return " ".join(self._starting_comment) @starting_comment.setter def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: @@ -313,6 +321,14 @@ def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) else: self._starting_comment = GameNodeComment(new_comment) + @property + def starting_comments(self) -> GameNodeComment: + return self._starting_comment + + @starting_comments.setter + def starting_comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: + self._starting_comment = new_comment + nags: Set[int] def __init__(self, *, comment: Union[str, list[str]] = "") -> None: @@ -539,7 +555,7 @@ def add_line(self, moves: Iterable[chess.Move], *, comment: Union[str, list[str] starting_comment = "" # Merge comment and NAGs. - node.comment.append(comment) + node.comments.append(comment) node.nags.update(nags) return node @@ -551,7 +567,7 @@ def eval(self) -> Optional[chess.engine.PovScore]: Complexity is `O(n)`. """ - match = EVAL_REGEX.search(" ".join(self.comment)) + match = EVAL_REGEX.search(self.comment) if not match: return None @@ -577,7 +593,7 @@ def eval_depth(self) -> Optional[int]: Complexity is `O(1)`. """ - match = EVAL_REGEX.search(" ".join(self.comment)) + match = EVAL_REGEX.search(self.comment) return int(match.group("depth")) if match and match.group("depth") else None def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] = None) -> None: @@ -595,15 +611,15 @@ def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] eval = f"[%eval #{score.white().mate()}{depth_suffix}]" found = 0 - for index in range(len(self.comment)): - self.comment[index], found = EVAL_REGEX.subn(_condense_affix(eval), self.comment[index], count=1) + for index in range(len(self.comments)): + self.comments[index], found = EVAL_REGEX.subn(_condense_affix(eval), self.comments[index], count=1) if found: break - self.comment.remove_empty() + self.comments.remove_empty() if not found and eval: - self.comment.append(eval) + self.comments.append(eval) def arrows(self) -> List[chess.svg.Arrow]: """ @@ -613,7 +629,7 @@ def arrows(self) -> List[chess.svg.Arrow]: Returns a list of :class:`arrows `. """ arrows = [] - for match in ARROWS_REGEX.finditer(" ".join(self.comment)): + for match in ARROWS_REGEX.finditer(self.comment): for group in match.group("arrows").split(","): arrows.append(chess.svg.Arrow.from_pgn(group)) @@ -635,10 +651,10 @@ def set_arrows(self, arrows: Iterable[Union[chess.svg.Arrow, Tuple[Square, Squar pass (csl if arrow.tail == arrow.head else cal).append(arrow.pgn()) # type: ignore - for index in range(len(self.comment)): - self.comment[index] = ARROWS_REGEX.sub(_condense_affix(""), self.comment[index]) + for index in range(len(self.comments)): + self.comments[index] = ARROWS_REGEX.sub(_condense_affix(""), self.comments[index]) - self.comment.remove_empty() + self.comments.remove_empty() prefix = "" if csl: @@ -647,7 +663,7 @@ def set_arrows(self, arrows: Iterable[Union[chess.svg.Arrow, Tuple[Square, Squar prefix += f"[%cal {','.join(cal)}]" if prefix: - self.comment.insert(0, prefix) + self.comments.insert(0, prefix) def clock(self) -> Optional[float]: """ @@ -657,7 +673,7 @@ def clock(self) -> Optional[float]: Returns the player's remaining time to the next time control after this move, in seconds. """ - match = CLOCK_REGEX.search(" ".join(self.comment)) + match = CLOCK_REGEX.search(self.comment) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -677,15 +693,15 @@ def set_clock(self, seconds: Optional[float]) -> None: clk = f"[%clk {hours:d}:{minutes:02d}:{seconds_part}]" found = 0 - for index in range(len(self.comment)): - self.comment[index], found = CLOCK_REGEX.subn(_condense_affix(clk), self.comment[index], count=1) + for index in range(len(self.comments)): + self.comments[index], found = CLOCK_REGEX.subn(_condense_affix(clk), self.comments[index], count=1) if found: break - self.comment.remove_empty() + self.comments.remove_empty() if not found and clk: - self.comment.append(clk) + self.comments.append(clk) def emt(self) -> Optional[float]: """ @@ -695,7 +711,7 @@ def emt(self) -> Optional[float]: Returns the player's elapsed move time use for the comment of this move, in seconds. """ - match = EMT_REGEX.search(" ".join(self.comment)) + match = EMT_REGEX.search(" ".join(self.comments)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -715,15 +731,15 @@ def set_emt(self, seconds: Optional[float]) -> None: emt = f"[%emt {hours:d}:{minutes:02d}:{seconds_part}]" found = 0 - for index in range(len(self.comment)): - self.comment[index], found = EMT_REGEX.subn(_condense_affix(emt), self.comment[index], count=1) + for index in range(len(self.comments)): + self.comments[index], found = EMT_REGEX.subn(_condense_affix(emt), self.comments[index], count=1) if found: break - self.comment.remove_empty() + self.comments.remove_empty() if not found and emt: - self.comment.append(emt) + self.comments.append(emt) @abc.abstractmethod def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: @@ -868,7 +884,7 @@ def end(self) -> ChildNode: def _accept_node(self, parent_board: chess.Board, visitor: BaseVisitor[ResultT]) -> None: if self.starting_comment: - visitor.visit_comment(self.starting_comment) + visitor.visit_comment(self.starting_comments) visitor.visit_move(parent_board, self.move) @@ -879,8 +895,8 @@ def _accept_node(self, parent_board: chess.Board, visitor: BaseVisitor[ResultT]) for nag in sorted(self.nags): visitor.visit_nag(nag) - if self.comment: - visitor.visit_comment(self.comment) + if self.comments: + visitor.visit_comment(self.comments) def _accept(self, parent_board: chess.Board, visitor: BaseVisitor[ResultT], *, sidelines: bool = True) -> None: stack = [_AcceptFrame(self, sidelines=sidelines)] @@ -1011,8 +1027,8 @@ def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: board = self.board() visitor.visit_board(board) - if self.comment: - visitor.visit_comment(self.comment) + if self.comments: + visitor.visit_comment(self.comments) if self.variations: self.variations[0]._accept(board, visitor) @@ -1347,14 +1363,14 @@ def visit_comment(self, comment: GameNodeComment) -> None: # Add as a comment for the current node if in the middle of # a variation. Add as a comment for the game if the comment # starts before any move. - new_comment = self.variation_stack[-1].comment + comment - new_comment.remove_empty() - self.variation_stack[-1].comment = new_comment + new_comments = self.variation_stack[-1].comments + comment + new_comments.remove_empty() + self.variation_stack[-1].comments = new_comments else: # Otherwise, it is a starting comment. - new_comment = self.starting_comment + comment - new_comment.remove_empty() - self.starting_comment = new_comment + new_comments = self.starting_comment + comment + new_comments.remove_empty() + self.starting_comment = new_comments def visit_move(self, board: chess.Board, move: chess.Move) -> None: self.variation_stack[-1] = self.variation_stack[-1].add_variation(move) diff --git a/test.py b/test.py index ee770de0f..aa89cd2c5 100755 --- a/test.py +++ b/test.py @@ -2220,19 +2220,24 @@ def test_read_game_with_multicomment_move(self): game = chess.pgn.read_game(pgn) first_move = game.variation(0) self.assertEqual(first_move.comment, "A common opening") + self.assertEqual(first_move.comments, "A common opening") + self.assertEqual(first_move.comments, ["A common opening"]) second_move = first_move.variation(0) - self.assertEqual(second_move.comment, ["A common response", "An uncommon comment"]) - second_move.comment.pop() - self.assertEqual(second_move.comment, ["A common response"]) + self.assertEqual(second_move.comments, ["A common response", "An uncommon comment"]) + second_move.comments.pop() + self.assertEqual(second_move.comments, ["A common response"]) + self.assertEqual(second_move.comments, "A common response") self.assertEqual(second_move.comment, "A common response") - second_move.comment.append("A replaced comment") + second_move.comments.append("A replaced comment") multiple_comments = ["A common response", "A replaced comment"] - self.assertEqual(second_move.comment, multiple_comments) - for move_comment, test_comment in zip(second_move.comment, multiple_comments): + self.assertEqual(second_move.comments, multiple_comments) + for move_comment, test_comment in zip(second_move.comments, multiple_comments): self.assertEqual(move_comment, test_comment) - self.assertEqual(list(second_move.comment), multiple_comments) - second_move.comment.pop(0) - self.assertEqual(second_move.comment, ["A replaced comment"]) + self.assertEqual(list(second_move.comments), multiple_comments) + self.assertEqual(second_move.comment, " ".join(multiple_comments)) + second_move.comments.pop(0) + self.assertEqual(second_move.comments, ["A replaced comment"]) + self.assertEqual(second_move.comments, "A replaced comment") self.assertEqual(second_move.comment, "A replaced comment") def test_comment_at_eol(self): @@ -2845,22 +2850,24 @@ def test_annotations(self): self.assertTrue(game.clock() is None) clock = 12345 game.set_clock(clock) - self.assertEqual(game.comment, ["foo [%bar] baz", "[%clk 3:25:45]"]) + self.assertEqual(game.comment, "foo [%bar] baz [%clk 3:25:45]") + self.assertEqual(game.comments, ["foo [%bar] baz", "[%clk 3:25:45]"]) self.assertEqual(game.clock(), clock) self.assertTrue(game.eval() is None) game.set_eval(chess.engine.PovScore(chess.engine.Cp(-80), chess.WHITE)) - self.assertEqual(game.comment, ["foo [%bar] baz", "[%clk 3:25:45]", "[%eval -0.80]"]) + self.assertEqual(game.comments, ["foo [%bar] baz", "[%clk 3:25:45]", "[%eval -0.80]"]) self.assertEqual(game.eval().white().score(), -80) self.assertEqual(game.eval_depth(), None) game.set_eval(chess.engine.PovScore(chess.engine.Mate(1), chess.WHITE), 5) - self.assertEqual(game.comment, ["foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) + self.assertEqual(game.comments, ["foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) self.assertEqual(game.eval().white().mate(), 1) self.assertEqual(game.eval_depth(), 5) self.assertEqual(game.arrows(), []) game.set_arrows([(chess.A1, chess.A1), chess.svg.Arrow(chess.A1, chess.H1, color="red"), chess.svg.Arrow(chess.B1, chess.B8)]) - self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) + self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) + self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%eval #1,5]") arrows = game.arrows() self.assertEqual(len(arrows), 3) self.assertEqual(arrows[0].color, "green") @@ -2870,17 +2877,21 @@ def test_annotations(self): self.assertTrue(game.emt() is None) emt = 321 game.set_emt(emt) - self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]", "[%emt 0:05:21]"]) + self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]", "[%emt 0:05:21]"]) + self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%eval #1,5] [%emt 0:05:21]") self.assertEqual(game.emt(), emt) game.set_eval(None) - self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%emt 0:05:21]"]) + self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%emt 0:05:21]"]) + self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%emt 0:05:21]") game.set_emt(None) - self.assertEqual(game.comment, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]"]) + self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]"]) + self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45]") game.set_clock(None) game.set_arrows([]) + self.assertEqual(game.comments, "foo [%bar] baz") self.assertEqual(game.comment, "foo [%bar] baz") def test_eval(self): From 2761d7c2b129bb5c88b3ff59c2dbbc792863b172 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 20 Apr 2024 21:16:52 -0700 Subject: [PATCH 167/250] Fix typing errors --- chess/pgn.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 50984a64d..c70c47bc2 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -306,7 +306,10 @@ def comments(self) -> GameNodeComment: @comments.setter def comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self.comment = new_comment + if isinstance(new_comment, GameNodeComment): + self._comment = new_comment + else: + self._comment = GameNodeComment(new_comment) _starting_comment: GameNodeComment @@ -327,7 +330,10 @@ def starting_comments(self) -> GameNodeComment: @starting_comments.setter def starting_comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self._starting_comment = new_comment + if isinstance(new_comment, GameNodeComment): + self._starting_comment = new_comment + else: + self._starting_comment = GameNodeComment(new_comment) nags: Set[int] @@ -335,11 +341,11 @@ def __init__(self, *, comment: Union[str, list[str]] = "") -> None: self.parent = None self.move = None self.variations = [] - self.comment = GameNodeComment(comment) + self.comments = GameNodeComment(comment) # Deprecated: These should be properties of ChildNode, but need to # remain here for backwards compatibility. - self.starting_comment = GameNodeComment() + self.starting_comments = GameNodeComment() self.nags = set() @abc.abstractmethod @@ -804,8 +810,8 @@ class ChildNode(GameNode): """ @property - def starting_comment(self) -> GameNodeComment: - return self._starting_comment + def starting_comment(self) -> str: + return " ".join(self._starting_comment) @starting_comment.setter def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: @@ -827,7 +833,7 @@ def __init__(self, parent: GameNode, move: chess.Move, *, comment: Union[str, li self.parent.variations.append(self) self.nags.update(nags) - self.starting_comment = GameNodeComment(starting_comment) + self.starting_comments = GameNodeComment(starting_comment) def board(self) -> chess.Board: stack: List[chess.Move] = [] @@ -1374,7 +1380,7 @@ def visit_comment(self, comment: GameNodeComment) -> None: def visit_move(self, board: chess.Board, move: chess.Move) -> None: self.variation_stack[-1] = self.variation_stack[-1].add_variation(move) - self.variation_stack[-1].starting_comment = self.starting_comment + self.variation_stack[-1].starting_comments = self.starting_comment self.starting_comment = GameNodeComment() self.in_variation = True From f0baba73ba034d48cb734bf4c0848417396a633f Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sat, 20 Apr 2024 21:22:56 -0700 Subject: [PATCH 168/250] Consolidate repeated logic --- chess/pgn.py | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index c70c47bc2..6ff13fd7e 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -191,9 +191,9 @@ class GameNodeComment: A class that can hold one or more comments for a GameNode. """ - def __init__(self, comment: Union[str, list[str]] = ""): + def __init__(self, comment: Union[str, list[str], GameNodeComment] = ""): """Create a new comment.""" - self.set(comment) + self.set(comment._comments if isinstance(comment,GameNodeComment) else comment) def set(self, new_comment: Union[str, list[str]]) -> None: """Replace the comment with a new comment or a list of comments.""" @@ -295,10 +295,7 @@ def comment(self) -> str: @comment.setter def comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - if isinstance(new_comment, GameNodeComment): - self._comment = new_comment - else: - self._comment = GameNodeComment(new_comment) + self._comment = GameNodeComment(new_comment) @property def comments(self) -> GameNodeComment: @@ -306,10 +303,7 @@ def comments(self) -> GameNodeComment: @comments.setter def comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - if isinstance(new_comment, GameNodeComment): - self._comment = new_comment - else: - self._comment = GameNodeComment(new_comment) + self._comment = GameNodeComment(new_comment) _starting_comment: GameNodeComment @@ -319,10 +313,7 @@ def starting_comment(self) -> str: @starting_comment.setter def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - if isinstance(new_comment, GameNodeComment): - self._starting_comment = new_comment - else: - self._starting_comment = GameNodeComment(new_comment) + self._starting_comment = GameNodeComment(new_comment) @property def starting_comments(self) -> GameNodeComment: @@ -330,10 +321,7 @@ def starting_comments(self) -> GameNodeComment: @starting_comments.setter def starting_comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - if isinstance(new_comment, GameNodeComment): - self._starting_comment = new_comment - else: - self._starting_comment = GameNodeComment(new_comment) + self._starting_comment = GameNodeComment(new_comment) nags: Set[int] @@ -815,10 +803,7 @@ def starting_comment(self) -> str: @starting_comment.setter def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - if isinstance(new_comment, GameNodeComment): - self._starting_comment = new_comment - else: - self._starting_comment = GameNodeComment(new_comment) + self._starting_comment = GameNodeComment(new_comment) nags: Set[int] """ From f840f8e58e635d89ba810ffa08cb0f81d4925f79 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 21 Apr 2024 19:27:56 -0700 Subject: [PATCH 169/250] Revert unneeded code change --- chess/pgn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/pgn.py b/chess/pgn.py index 6ff13fd7e..e462a0750 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -705,7 +705,7 @@ def emt(self) -> Optional[float]: Returns the player's elapsed move time use for the comment of this move, in seconds. """ - match = EMT_REGEX.search(" ".join(self.comments)) + match = EMT_REGEX.search(self.comment) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) From 716a0b9459480b852b5169a0f1b0b3dbecd3be31 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 4 May 2024 17:44:20 +0200 Subject: [PATCH 170/250] Require that EPD opcodes start with letter (fixes #1080) --- chess/__init__.py | 16 +++++++++++++--- test.py | 5 +++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index f9a9ab7f5..bed9eec5d 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -2739,9 +2739,7 @@ def _epd_operations(self, operations: Mapping[str, Union[None, str, int, float, first_op = True for opcode, operand in operations.items(): - assert opcode != "-", "dash (-) is not a valid epd opcode" - for blacklisted in [" ", "\n", "\t", "\r"]: - assert blacklisted not in opcode, f"invalid character {blacklisted!r} in epd opcode: {opcode!r}" + self._validate_epd_opcode(opcode) if not first_op: epd.append(" ") @@ -2819,6 +2817,17 @@ def epd(self, *, shredder: bool = False, en_passant: EnPassantSpec = "legal", pr return " ".join(epd) + def _validate_epd_opcode(self, opcode: str) -> None: + if not opcode: + raise ValueError("empty string is not a valid epd opcode") + if opcode == "-": + raise ValueError("dash (-) is not a valid epd opcode") + if not opcode[0].isalpha(): + raise ValueError(f"expected epd opcode to start with a letter, got: {opcode!r}") + for blacklisted in [" ", "\n", "\t", "\r"]: + if blacklisted in opcode: + raise ValueError(f"invalid character {blacklisted!r} in epd opcode: {opcode!r}") + def _parse_epd_ops(self: BoardT, operation_part: str, make_board: Callable[[], BoardT]) -> Dict[str, Union[None, str, int, float, Move, List[Move]]]: operations: Dict[str, Union[None, str, int, float, Move, List[Move]]] = {} state = "opcode" @@ -2832,6 +2841,7 @@ def _parse_epd_ops(self: BoardT, operation_part: str, make_board: Callable[[], B if opcode == "-": opcode = "" elif opcode: + self._validate_epd_opcode(opcode) state = "after_opcode" elif ch is None or ch == ";": if opcode == "-": diff --git a/test.py b/test.py index 8dbc95a25..4ca3be6c2 100755 --- a/test.py +++ b/test.py @@ -1143,6 +1143,11 @@ def test_eret_epd(self): self.assertEqual(ops["id"], "ERET 001 - Entlastung") self.assertEqual(ops["bm"], [chess.Move.from_uci("f1f4")]) + def test_set_fen_as_epd(self): + board = chess.Board() + with self.assertRaises(ValueError): + board.set_epd(board.fen()) # Move numbers are not valid opcodes + def test_null_moves(self): self.assertEqual(str(chess.Move.null()), "0000") self.assertEqual(chess.Move.null().uci(), "0000") From df714e39a559135c51228cca6a7cb5c716756ee3 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 4 May 2024 17:59:31 +0200 Subject: [PATCH 171/250] Fixup invalid EPDs in chess960.perft file --- examples/perft/chess960.perft | 1920 ++++++++++++++++----------------- 1 file changed, 960 insertions(+), 960 deletions(-) diff --git a/examples/perft/chess960.perft b/examples/perft/chess960.perft index 76be26eed..12276f256 100644 --- a/examples/perft/chess960.perft +++ b/examples/perft/chess960.perft @@ -2,7 +2,7 @@ # https://github.com/AndyGrant/Ethereal/blob/master/src/perft/fischer.epd id 0 -epd bqnb1rkr/pp3ppp/3ppn2/2p5/5P2/P2P4/NPP1P1PP/BQ1BNRKR w HFhf - 2 9 +epd bqnb1rkr/pp3ppp/3ppn2/2p5/5P2/P2P4/NPP1P1PP/BQ1BNRKR w HFhf - perft 1 21 perft 2 528 perft 3 12189 @@ -11,7 +11,7 @@ perft 5 8146062 perft 6 227689589 id 1 -epd 2nnrbkr/p1qppppp/8/1ppb4/6PP/3PP3/PPP2P2/BQNNRBKR w HEhe - 1 9 +epd 2nnrbkr/p1qppppp/8/1ppb4/6PP/3PP3/PPP2P2/BQNNRBKR w HEhe - perft 1 21 perft 2 807 perft 3 18002 @@ -20,7 +20,7 @@ perft 5 16253601 perft 6 590751109 id 2 -epd b1q1rrkb/pppppppp/3nn3/8/P7/1PPP4/4PPPP/BQNNRKRB w GE - 1 9 +epd b1q1rrkb/pppppppp/3nn3/8/P7/1PPP4/4PPPP/BQNNRKRB w GE - perft 1 20 perft 2 479 perft 3 10471 @@ -29,7 +29,7 @@ perft 5 6417013 perft 6 177654692 id 3 -epd qbbnnrkr/2pp2pp/p7/1p2pp2/8/P3PP2/1PPP1KPP/QBBNNR1R w hf - 0 9 +epd qbbnnrkr/2pp2pp/p7/1p2pp2/8/P3PP2/1PPP1KPP/QBBNNR1R w hf - perft 1 22 perft 2 593 perft 3 13440 @@ -38,7 +38,7 @@ perft 5 9183776 perft 6 274103539 id 4 -epd 1nbbnrkr/p1p1ppp1/3p4/1p3P1p/3Pq2P/8/PPP1P1P1/QNBBNRKR w HFhf - 0 9 +epd 1nbbnrkr/p1p1ppp1/3p4/1p3P1p/3Pq2P/8/PPP1P1P1/QNBBNRKR w HFhf - perft 1 28 perft 2 1120 perft 3 31058 @@ -47,7 +47,7 @@ perft 5 34030312 perft 6 1250970898 id 5 -epd qnbnr1kr/ppp1b1pp/4p3/3p1p2/8/2NPP3/PPP1BPPP/QNB1R1KR w HEhe - 1 9 +epd qnbnr1kr/ppp1b1pp/4p3/3p1p2/8/2NPP3/PPP1BPPP/QNB1R1KR w HEhe - perft 1 29 perft 2 899 perft 3 26578 @@ -56,7 +56,7 @@ perft 5 24851983 perft 6 775718317 id 6 -epd q1bnrkr1/ppppp2p/2n2p2/4b1p1/2NP4/8/PPP1PPPP/QNB1RRKB w ge - 1 9 +epd q1bnrkr1/ppppp2p/2n2p2/4b1p1/2NP4/8/PPP1PPPP/QNB1RRKB w ge - perft 1 30 perft 2 860 perft 3 24566 @@ -65,7 +65,7 @@ perft 5 21093346 perft 6 649209803 id 7 -epd qbn1brkr/ppp1p1p1/2n4p/3p1p2/P7/6PP/QPPPPP2/1BNNBRKR w HFhf - 0 9 +epd qbn1brkr/ppp1p1p1/2n4p/3p1p2/P7/6PP/QPPPPP2/1BNNBRKR w HFhf - perft 1 25 perft 2 635 perft 3 17054 @@ -74,7 +74,7 @@ perft 5 13203304 perft 6 377184252 id 8 -epd qnnbbrkr/1p2ppp1/2pp3p/p7/1P5P/2NP4/P1P1PPP1/Q1NBBRKR w HFhf - 0 9 +epd qnnbbrkr/1p2ppp1/2pp3p/p7/1P5P/2NP4/P1P1PPP1/Q1NBBRKR w HFhf - perft 1 24 perft 2 572 perft 3 15243 @@ -83,7 +83,7 @@ perft 5 11110203 perft 6 293989890 id 9 -epd qn1rbbkr/ppp2p1p/1n1pp1p1/8/3P4/P6P/1PP1PPPK/QNNRBB1R w hd - 2 9 +epd qn1rbbkr/ppp2p1p/1n1pp1p1/8/3P4/P6P/1PP1PPPK/QNNRBB1R w hd - perft 1 28 perft 2 811 perft 3 23175 @@ -92,7 +92,7 @@ perft 5 19836606 perft 6 594527992 id 10 -epd qnr1bkrb/pppp2pp/3np3/5p2/8/P2P2P1/NPP1PP1P/QN1RBKRB w GDg - 3 9 +epd qnr1bkrb/pppp2pp/3np3/5p2/8/P2P2P1/NPP1PP1P/QN1RBKRB w GDg - perft 1 33 perft 2 823 perft 3 26895 @@ -101,7 +101,7 @@ perft 5 23114629 perft 6 646390782 id 11 -epd qb1nrkbr/1pppp1p1/1n3p2/p1B4p/8/3P1P1P/PPP1P1P1/QBNNRK1R w HEhe - 0 9 +epd qb1nrkbr/1pppp1p1/1n3p2/p1B4p/8/3P1P1P/PPP1P1P1/QBNNRK1R w HEhe - perft 1 31 perft 2 855 perft 3 25620 @@ -110,7 +110,7 @@ perft 5 21796206 perft 6 651054626 id 12 -epd qnnbrk1r/1p1ppbpp/2p5/p4p2/2NP3P/8/PPP1PPP1/Q1NBRKBR w HEhe - 0 9 +epd qnnbrk1r/1p1ppbpp/2p5/p4p2/2NP3P/8/PPP1PPP1/Q1NBRKBR w HEhe - perft 1 26 perft 2 790 perft 3 21238 @@ -119,7 +119,7 @@ perft 5 17819770 perft 6 544866674 id 13 -epd 1qnrkbbr/1pppppp1/p1n4p/8/P7/1P1N1P2/2PPP1PP/QN1RKBBR w HDhd - 0 9 +epd 1qnrkbbr/1pppppp1/p1n4p/8/P7/1P1N1P2/2PPP1PP/QN1RKBBR w HDhd - perft 1 37 perft 2 883 perft 3 32187 @@ -128,7 +128,7 @@ perft 5 29370838 perft 6 783201510 id 14 -epd qn1rkrbb/pp1p1ppp/2p1p3/3n4/4P2P/2NP4/PPP2PP1/Q1NRKRBB w FDfd - 1 9 +epd qn1rkrbb/pp1p1ppp/2p1p3/3n4/4P2P/2NP4/PPP2PP1/Q1NRKRBB w FDfd - perft 1 24 perft 2 585 perft 3 14769 @@ -137,7 +137,7 @@ perft 5 9482310 perft 6 233468620 id 15 -epd bb1qnrkr/pp1p1pp1/1np1p3/4N2p/8/1P4P1/P1PPPP1P/BBNQ1RKR w HFhf - 0 9 +epd bb1qnrkr/pp1p1pp1/1np1p3/4N2p/8/1P4P1/P1PPPP1P/BBNQ1RKR w HFhf - perft 1 29 perft 2 864 perft 3 25747 @@ -146,7 +146,7 @@ perft 5 24219627 perft 6 776836316 id 16 -epd bnqbnr1r/p1p1ppkp/3p4/1p4p1/P7/3NP2P/1PPP1PP1/BNQB1RKR w HF - 0 9 +epd bnqbnr1r/p1p1ppkp/3p4/1p4p1/P7/3NP2P/1PPP1PP1/BNQB1RKR w HF - perft 1 26 perft 2 889 perft 3 24353 @@ -155,7 +155,7 @@ perft 5 23701014 perft 6 809194268 id 17 -epd bnqnrbkr/1pp2pp1/p7/3pP2p/4P1P1/8/PPPP3P/BNQNRBKR w HEhe d6 0 9 +epd bnqnrbkr/1pp2pp1/p7/3pP2p/4P1P1/8/PPPP3P/BNQNRBKR w HEhe d6 perft 1 31 perft 2 984 perft 3 28677 @@ -164,7 +164,7 @@ perft 5 29032175 perft 6 1008880643 id 18 -epd b1qnrrkb/ppp1pp1p/n2p1Pp1/8/8/P7/1PPPP1PP/BNQNRKRB w GE - 0 9 +epd b1qnrrkb/ppp1pp1p/n2p1Pp1/8/8/P7/1PPPP1PP/BNQNRKRB w GE - perft 1 20 perft 2 484 perft 3 10532 @@ -173,7 +173,7 @@ perft 5 6718715 perft 6 193594729 id 19 -epd n1bqnrkr/pp1ppp1p/2p5/6p1/2P2b2/PN6/1PNPPPPP/1BBQ1RKR w HFhf - 2 9 +epd n1bqnrkr/pp1ppp1p/2p5/6p1/2P2b2/PN6/1PNPPPPP/1BBQ1RKR w HFhf - perft 1 23 perft 2 732 perft 3 17746 @@ -182,7 +182,7 @@ perft 5 14481581 perft 6 457140569 id 20 -epd n1bb1rkr/qpnppppp/2p5/p7/P1P5/5P2/1P1PPRPP/NQBBN1KR w Hhf - 1 9 +epd n1bb1rkr/qpnppppp/2p5/p7/P1P5/5P2/1P1PPRPP/NQBBN1KR w Hhf - perft 1 27 perft 2 697 perft 3 18724 @@ -191,7 +191,7 @@ perft 5 14226907 perft 6 400942568 id 21 -epd nqb1rbkr/pppppp1p/4n3/6p1/4P3/1NP4P/PP1P1PP1/1QBNRBKR w HEhe - 1 9 +epd nqb1rbkr/pppppp1p/4n3/6p1/4P3/1NP4P/PP1P1PP1/1QBNRBKR w HEhe - perft 1 28 perft 2 641 perft 3 18811 @@ -200,7 +200,7 @@ perft 5 13780398 perft 6 354122358 id 22 -epd n1bnrrkb/pp1pp2p/2p2p2/6p1/5B2/3P4/PPP1PPPP/NQ1NRKRB w GE - 2 9 +epd n1bnrrkb/pp1pp2p/2p2p2/6p1/5B2/3P4/PPP1PPPP/NQ1NRKRB w GE - perft 1 28 perft 2 606 perft 3 16883 @@ -209,7 +209,7 @@ perft 5 10815324 perft 6 254026570 id 23 -epd nbqnbrkr/2ppp1p1/pp3p1p/8/4N2P/1N6/PPPPPPP1/1BQ1BRKR w HFhf - 0 9 +epd nbqnbrkr/2ppp1p1/pp3p1p/8/4N2P/1N6/PPPPPPP1/1BQ1BRKR w HFhf - perft 1 26 perft 2 626 perft 3 17268 @@ -218,7 +218,7 @@ perft 5 12719546 perft 6 339132046 id 24 -epd nq1bbrkr/pp2nppp/2pp4/4p3/1PP1P3/1B6/P2P1PPP/NQN1BRKR w HFhf - 2 9 +epd nq1bbrkr/pp2nppp/2pp4/4p3/1PP1P3/1B6/P2P1PPP/NQN1BRKR w HFhf - perft 1 21 perft 2 504 perft 3 11812 @@ -227,7 +227,7 @@ perft 5 7697880 perft 6 207028745 id 25 -epd nqnrb1kr/2pp1ppp/1p1bp3/p1B5/5P2/3N4/PPPPP1PP/NQ1R1BKR w HDhd - 0 9 +epd nqnrb1kr/2pp1ppp/1p1bp3/p1B5/5P2/3N4/PPPPP1PP/NQ1R1BKR w HDhd - perft 1 30 perft 2 672 perft 3 19307 @@ -236,7 +236,7 @@ perft 5 13454573 perft 6 345445468 id 26 -epd nqn2krb/p1prpppp/1pbp4/7P/5P2/8/PPPPPKP1/NQNRB1RB w g - 3 9 +epd nqn2krb/p1prpppp/1pbp4/7P/5P2/8/PPPPPKP1/NQNRB1RB w g - perft 1 21 perft 2 461 perft 3 10608 @@ -245,7 +245,7 @@ perft 5 6194124 perft 6 152861936 id 27 -epd nb1n1kbr/ppp1rppp/3pq3/P3p3/8/4P3/1PPPRPPP/NBQN1KBR w Hh - 1 9 +epd nb1n1kbr/ppp1rppp/3pq3/P3p3/8/4P3/1PPPRPPP/NBQN1KBR w Hh - perft 1 19 perft 2 566 perft 3 11786 @@ -254,7 +254,7 @@ perft 5 8047916 perft 6 249171636 id 28 -epd nqnbrkbr/1ppppp1p/p7/6p1/6P1/P6P/1PPPPP2/NQNBRKBR w HEhe - 1 9 +epd nqnbrkbr/1ppppp1p/p7/6p1/6P1/P6P/1PPPPP2/NQNBRKBR w HEhe - perft 1 20 perft 2 382 perft 3 8694 @@ -263,7 +263,7 @@ perft 5 4708975 perft 6 112278808 id 29 -epd nq1rkb1r/pp1pp1pp/1n2bp1B/2p5/8/5P1P/PPPPP1P1/NQNRKB1R w HDhd - 2 9 +epd nq1rkb1r/pp1pp1pp/1n2bp1B/2p5/8/5P1P/PPPPP1P1/NQNRKB1R w HDhd - perft 1 24 perft 2 809 perft 3 20090 @@ -272,7 +272,7 @@ perft 5 17647882 perft 6 593457788 id 30 -epd nqnrkrb1/pppppp2/7p/4b1p1/8/PN1NP3/1PPP1PPP/1Q1RKRBB w FDfd - 1 9 +epd nqnrkrb1/pppppp2/7p/4b1p1/8/PN1NP3/1PPP1PPP/1Q1RKRBB w FDfd - perft 1 26 perft 2 683 perft 3 18102 @@ -281,7 +281,7 @@ perft 5 13055173 perft 6 352398011 id 31 -epd bb1nqrkr/1pp1ppp1/pn5p/3p4/8/P2NNP2/1PPPP1PP/BB2QRKR w HFhf - 0 9 +epd bb1nqrkr/1pp1ppp1/pn5p/3p4/8/P2NNP2/1PPPP1PP/BB2QRKR w HFhf - perft 1 29 perft 2 695 perft 3 21193 @@ -290,7 +290,7 @@ perft 5 17454857 perft 6 483785639 id 32 -epd bnn1qrkr/pp1ppp1p/2p5/b3Q1p1/8/5P1P/PPPPP1P1/BNNB1RKR w HFhf - 2 9 +epd bnn1qrkr/pp1ppp1p/2p5/b3Q1p1/8/5P1P/PPPPP1P1/BNNB1RKR w HFhf - perft 1 44 perft 2 920 perft 3 35830 @@ -299,7 +299,7 @@ perft 5 29742670 perft 6 702867204 id 33 -epd bnnqrbkr/pp1p2p1/2p1p2p/5p2/1P5P/1R6/P1PPPPP1/BNNQRBK1 w Ehe - 0 9 +epd bnnqrbkr/pp1p2p1/2p1p2p/5p2/1P5P/1R6/P1PPPPP1/BNNQRBK1 w Ehe - perft 1 33 perft 2 1022 perft 3 32724 @@ -308,7 +308,7 @@ perft 5 32898113 perft 6 1047360456 id 34 -epd b1nqrkrb/2pppppp/p7/1P6/1n6/P4P2/1P1PP1PP/BNNQRKRB w GEge - 0 9 +epd b1nqrkrb/2pppppp/p7/1P6/1n6/P4P2/1P1PP1PP/BNNQRKRB w GEge - perft 1 23 perft 2 638 perft 3 15744 @@ -317,7 +317,7 @@ perft 5 11735969 perft 6 344211589 id 35 -epd n1bnqrkr/3ppppp/1p6/pNp1b3/2P3P1/8/PP1PPP1P/NBB1QRKR w HFhf - 1 9 +epd n1bnqrkr/3ppppp/1p6/pNp1b3/2P3P1/8/PP1PPP1P/NBB1QRKR w HFhf - perft 1 29 perft 2 728 perft 3 20768 @@ -326,7 +326,7 @@ perft 5 15621236 perft 6 415766465 id 36 -epd n2bqrkr/p1p1pppp/1pn5/3p1b2/P6P/1NP5/1P1PPPP1/1NBBQRKR w HFhf - 3 9 +epd n2bqrkr/p1p1pppp/1pn5/3p1b2/P6P/1NP5/1P1PPPP1/1NBBQRKR w HFhf - perft 1 20 perft 2 533 perft 3 12152 @@ -335,7 +335,7 @@ perft 5 8088751 perft 6 223068417 id 37 -epd nnbqrbkr/1pp1p1p1/p2p4/5p1p/2P1P3/N7/PPQP1PPP/N1B1RBKR w HEhe - 0 9 +epd nnbqrbkr/1pp1p1p1/p2p4/5p1p/2P1P3/N7/PPQP1PPP/N1B1RBKR w HEhe - perft 1 27 perft 2 619 perft 3 18098 @@ -344,7 +344,7 @@ perft 5 13755384 perft 6 357222394 id 38 -epd nnbqrkr1/pp1pp2p/2p2b2/5pp1/1P5P/4P1P1/P1PP1P2/NNBQRKRB w GEge - 1 9 +epd nnbqrkr1/pp1pp2p/2p2b2/5pp1/1P5P/4P1P1/P1PP1P2/NNBQRKRB w GEge - perft 1 32 perft 2 1046 perft 3 33721 @@ -353,7 +353,7 @@ perft 5 36218182 perft 6 1202830851 id 39 -epd nb1qbrkr/p1pppp2/1p1n2pp/8/1P6/2PN3P/P2PPPP1/NB1QBRKR w HFhf - 0 9 +epd nb1qbrkr/p1pppp2/1p1n2pp/8/1P6/2PN3P/P2PPPP1/NB1QBRKR w HFhf - perft 1 25 perft 2 521 perft 3 14021 @@ -362,7 +362,7 @@ perft 5 8697700 perft 6 201455191 id 40 -epd nnq1brkr/pp1pppp1/8/2p4P/8/5K2/PPPbPP1P/NNQBBR1R w hf - 0 9 +epd nnq1brkr/pp1pppp1/8/2p4P/8/5K2/PPPbPP1P/NNQBBR1R w hf - perft 1 23 perft 2 724 perft 3 18263 @@ -371,7 +371,7 @@ perft 5 15338230 perft 6 484638597 id 41 -epd nnqrbb1r/pppppk2/5pp1/7p/1P6/3P2PP/P1P1PP2/NNQRBBKR w HD - 0 9 +epd nnqrbb1r/pppppk2/5pp1/7p/1P6/3P2PP/P1P1PP2/NNQRBBKR w HD - perft 1 30 perft 2 717 perft 3 21945 @@ -380,7 +380,7 @@ perft 5 17166700 perft 6 450069742 id 42 -epd nnqr1krb/p1p1pppp/2bp4/8/1p1P4/4P3/PPP2PPP/NNQRBKRB w GDgd - 0 9 +epd nnqr1krb/p1p1pppp/2bp4/8/1p1P4/4P3/PPP2PPP/NNQRBKRB w GDgd - perft 1 25 perft 2 873 perft 3 20796 @@ -389,7 +389,7 @@ perft 5 18162741 perft 6 641708630 id 43 -epd nbnqrkbr/p2ppp2/1p4p1/2p4p/3P3P/3N4/PPP1PPPR/NB1QRKB1 w Ehe - 0 9 +epd nbnqrkbr/p2ppp2/1p4p1/2p4p/3P3P/3N4/PPP1PPPR/NB1QRKB1 w Ehe - perft 1 24 perft 2 589 perft 3 15190 @@ -398,7 +398,7 @@ perft 5 10630667 perft 6 279474189 id 44 -epd n1qbrkbr/p1ppp2p/2n2pp1/1p6/1P6/2P3P1/P2PPP1P/NNQBRKBR w HEhe - 0 9 +epd n1qbrkbr/p1ppp2p/2n2pp1/1p6/1P6/2P3P1/P2PPP1P/NNQBRKBR w HEhe - perft 1 22 perft 2 592 perft 3 14269 @@ -407,7 +407,7 @@ perft 5 10356818 perft 6 301583306 id 45 -epd 2qrkbbr/ppn1pppp/n1p5/3p4/5P2/P1PP4/1P2P1PP/NNQRKBBR w HDhd - 1 9 +epd 2qrkbbr/ppn1pppp/n1p5/3p4/5P2/P1PP4/1P2P1PP/NNQRKBBR w HDhd - perft 1 27 perft 2 750 perft 3 20584 @@ -416,7 +416,7 @@ perft 5 16819085 perft 6 516796736 id 46 -epd 1nqr1rbb/pppkp1pp/1n3p2/3p4/1P6/5P1P/P1PPPKP1/NNQR1RBB w - - 1 9 +epd 1nqr1rbb/pppkp1pp/1n3p2/3p4/1P6/5P1P/P1PPPKP1/NNQR1RBB w - - perft 1 24 perft 2 623 perft 3 15921 @@ -425,7 +425,7 @@ perft 5 11594634 perft 6 322745925 id 47 -epd bbn1rqkr/pp1pp2p/4npp1/2p5/1P6/2BPP3/P1P2PPP/1BNNRQKR w HEhe - 0 9 +epd bbn1rqkr/pp1pp2p/4npp1/2p5/1P6/2BPP3/P1P2PPP/1BNNRQKR w HEhe - perft 1 23 perft 2 730 perft 3 17743 @@ -434,7 +434,7 @@ perft 5 14496370 perft 6 468608864 id 48 -epd bn1brqkr/pppp2p1/3npp2/7p/PPP5/8/3PPPPP/BNNBRQKR w HEhe - 0 9 +epd bn1brqkr/pppp2p1/3npp2/7p/PPP5/8/3PPPPP/BNNBRQKR w HEhe - perft 1 25 perft 2 673 perft 3 17835 @@ -443,7 +443,7 @@ perft 5 14284338 perft 6 434008567 id 49 -epd bn1rqbkr/ppp1ppp1/1n6/2p4p/7P/3P4/PPP1PPP1/BN1RQBKR w HDhd - 0 9 +epd bn1rqbkr/ppp1ppp1/1n6/2p4p/7P/3P4/PPP1PPP1/BN1RQBKR w HDhd - perft 1 25 perft 2 776 perft 3 20562 @@ -452,7 +452,7 @@ perft 5 18486027 perft 6 616653869 id 50 -epd bnnr1krb/ppp2ppp/3p4/3Bp3/q1P3PP/8/PP1PPP2/BNNRQKR1 w GDgd - 0 9 +epd bnnr1krb/ppp2ppp/3p4/3Bp3/q1P3PP/8/PP1PPP2/BNNRQKR1 w GDgd - perft 1 29 perft 2 1040 perft 3 30772 @@ -461,7 +461,7 @@ perft 5 31801525 perft 6 1075147725 id 51 -epd 1bbnrqkr/pp1ppppp/8/2p5/n7/3PNPP1/PPP1P2P/NBB1RQKR w HEhe - 1 9 +epd 1bbnrqkr/pp1ppppp/8/2p5/n7/3PNPP1/PPP1P2P/NBB1RQKR w HEhe - perft 1 24 perft 2 598 perft 3 15673 @@ -470,7 +470,7 @@ perft 5 11394778 perft 6 310589129 id 52 -epd nnbbrqkr/p2ppp1p/1pp5/8/6p1/N1P5/PPBPPPPP/N1B1RQKR w HEhe - 0 9 +epd nnbbrqkr/p2ppp1p/1pp5/8/6p1/N1P5/PPBPPPPP/N1B1RQKR w HEhe - perft 1 26 perft 2 530 perft 3 14031 @@ -479,7 +479,7 @@ perft 5 8846766 perft 6 229270702 id 53 -epd nnbrqbkr/2p1p1pp/p4p2/1p1p4/8/NP6/P1PPPPPP/N1BRQBKR w HDhd - 0 9 +epd nnbrqbkr/2p1p1pp/p4p2/1p1p4/8/NP6/P1PPPPPP/N1BRQBKR w HDhd - perft 1 17 perft 2 496 perft 3 10220 @@ -488,7 +488,7 @@ perft 5 7103549 perft 6 217108001 id 54 -epd nnbrqk1b/pp2pprp/2pp2p1/8/3PP1P1/8/PPP2P1P/NNBRQRKB w d - 1 9 +epd nnbrqk1b/pp2pprp/2pp2p1/8/3PP1P1/8/PPP2P1P/NNBRQRKB w d - perft 1 33 perft 2 820 perft 3 27856 @@ -497,7 +497,7 @@ perft 5 24714401 perft 6 645835197 id 55 -epd 1bnrbqkr/ppnpp1p1/2p2p1p/8/1P6/4PPP1/P1PP3P/NBNRBQKR w HDhd - 0 9 +epd 1bnrbqkr/ppnpp1p1/2p2p1p/8/1P6/4PPP1/P1PP3P/NBNRBQKR w HDhd - perft 1 27 perft 2 705 perft 3 19760 @@ -506,7 +506,7 @@ perft 5 15964771 perft 6 464662032 id 56 -epd n1rbbqkr/pp1pppp1/7p/P1p5/1n6/2PP4/1P2PPPP/NNRBBQKR w HChc - 0 9 +epd n1rbbqkr/pp1pppp1/7p/P1p5/1n6/2PP4/1P2PPPP/NNRBBQKR w HChc - perft 1 22 perft 2 631 perft 3 14978 @@ -515,7 +515,7 @@ perft 5 10911545 perft 6 320838556 id 57 -epd n1rqb1kr/p1pppp1p/1pn4b/3P2p1/P7/1P6/2P1PPPP/NNRQBBKR w HChc - 0 9 +epd n1rqb1kr/p1pppp1p/1pn4b/3P2p1/P7/1P6/2P1PPPP/NNRQBBKR w HChc - perft 1 24 perft 2 477 perft 3 12506 @@ -524,7 +524,7 @@ perft 5 7419372 perft 6 165945904 id 58 -epd nnrqbkrb/pppp1pp1/7p/4p3/6P1/2N2B2/PPPPPP1P/NR1QBKR1 w Ggc - 2 9 +epd nnrqbkrb/pppp1pp1/7p/4p3/6P1/2N2B2/PPPPPP1P/NR1QBKR1 w Ggc - perft 1 29 perft 2 658 perft 3 19364 @@ -533,7 +533,7 @@ perft 5 14233587 perft 6 373744834 id 59 -epd n1nrqkbr/ppb2ppp/3pp3/2p5/2P3P1/5P2/PP1PPB1P/NBNRQK1R w HDhd - 1 9 +epd n1nrqkbr/ppb2ppp/3pp3/2p5/2P3P1/5P2/PP1PPB1P/NBNRQK1R w HDhd - perft 1 32 perft 2 801 perft 3 25861 @@ -542,7 +542,7 @@ perft 5 22318948 perft 6 619857455 id 60 -epd 2rbqkbr/p1pppppp/1nn5/1p6/7P/P4P2/1PPPP1PB/NNRBQK1R w HChc - 2 9 +epd 2rbqkbr/p1pppppp/1nn5/1p6/7P/P4P2/1PPPP1PB/NNRBQK1R w HChc - perft 1 27 perft 2 647 perft 3 18030 @@ -551,7 +551,7 @@ perft 5 13189156 perft 6 354689323 id 61 -epd nn1qkbbr/pp2ppp1/2rp4/2p4p/P2P4/1N5P/1PP1PPP1/1NRQKBBR w HCh - 1 9 +epd nn1qkbbr/pp2ppp1/2rp4/2p4p/P2P4/1N5P/1PP1PPP1/1NRQKBBR w HCh - perft 1 24 perft 2 738 perft 3 18916 @@ -560,7 +560,7 @@ perft 5 16420659 perft 6 519075930 id 62 -epd nnrqk1bb/p1ppp2p/5rp1/1p3p2/1P4P1/5P1P/P1PPP3/NNRQKRBB w FCc - 1 9 +epd nnrqk1bb/p1ppp2p/5rp1/1p3p2/1P4P1/5P1P/P1PPP3/NNRQKRBB w FCc - perft 1 25 perft 2 795 perft 3 20510 @@ -569,7 +569,7 @@ perft 5 17342527 perft 6 556144017 id 63 -epd bb1nrkqr/ppppn2p/4ppp1/8/1P4P1/4P3/P1PPKP1P/BBNNR1QR w he - 0 9 +epd bb1nrkqr/ppppn2p/4ppp1/8/1P4P1/4P3/P1PPKP1P/BBNNR1QR w he - perft 1 29 perft 2 664 perft 3 20024 @@ -578,7 +578,7 @@ perft 5 15373803 perft 6 406016364 id 64 -epd bnnbrkqr/1p1ppp2/8/p1p3pp/1P6/N4P2/PBPPP1PP/2NBRKQR w HEhe - 0 9 +epd bnnbrkqr/1p1ppp2/8/p1p3pp/1P6/N4P2/PBPPP1PP/2NBRKQR w HEhe - perft 1 31 perft 2 770 perft 3 24850 @@ -587,7 +587,7 @@ perft 5 22562080 perft 6 662029574 id 65 -epd 1nnrkbqr/p1pp1ppp/4p3/1p6/1Pb1P3/6PB/P1PP1P1P/BNNRK1QR w HDhd - 0 9 +epd 1nnrkbqr/p1pp1ppp/4p3/1p6/1Pb1P3/6PB/P1PP1P1P/BNNRK1QR w HDhd - perft 1 27 perft 2 776 perft 3 22133 @@ -596,7 +596,7 @@ perft 5 19153245 perft 6 562738257 id 66 -epd bnr1kqrb/pppp1pp1/1n5p/4p3/P3P3/3P2P1/1PP2P1P/BNNRKQRB w GDg - 0 9 +epd bnr1kqrb/pppp1pp1/1n5p/4p3/P3P3/3P2P1/1PP2P1P/BNNRKQRB w GDg - perft 1 26 perft 2 624 perft 3 16411 @@ -605,7 +605,7 @@ perft 5 11906515 perft 6 338092952 id 67 -epd nbbnrkqr/p1ppp1pp/1p3p2/8/2P5/4P3/PP1P1PPP/NBBNRKQR w HEhe - 1 9 +epd nbbnrkqr/p1ppp1pp/1p3p2/8/2P5/4P3/PP1P1PPP/NBBNRKQR w HEhe - perft 1 25 perft 2 624 perft 3 15561 @@ -614,7 +614,7 @@ perft 5 10817378 perft 6 311138112 id 68 -epd nn1brkqr/pp1bpppp/8/2pp4/P4P2/1PN5/2PPP1PP/N1BBRKQR w HEhe - 1 9 +epd nn1brkqr/pp1bpppp/8/2pp4/P4P2/1PN5/2PPP1PP/N1BBRKQR w HEhe - perft 1 23 perft 2 659 perft 3 16958 @@ -623,7 +623,7 @@ perft 5 13242252 perft 6 373557073 id 69 -epd n1brkbqr/ppp1pp1p/6pB/3p4/2Pn4/8/PP2PPPP/NN1RKBQR w HDhd - 0 9 +epd n1brkbqr/ppp1pp1p/6pB/3p4/2Pn4/8/PP2PPPP/NN1RKBQR w HDhd - perft 1 32 perft 2 1026 perft 3 30360 @@ -632,7 +632,7 @@ perft 5 29436320 perft 6 957904151 id 70 -epd nnbrkqrb/p2ppp2/Q5pp/1pp5/4PP2/2N5/PPPP2PP/N1BRK1RB w GDgd - 0 9 +epd nnbrkqrb/p2ppp2/Q5pp/1pp5/4PP2/2N5/PPPP2PP/N1BRK1RB w GDgd - perft 1 36 perft 2 843 perft 3 29017 @@ -641,7 +641,7 @@ perft 5 24321197 perft 6 630396940 id 71 -epd nbnrbk1r/pppppppq/8/7p/8/1N2QPP1/PPPPP2P/NB1RBK1R w HDhd - 2 9 +epd nbnrbk1r/pppppppq/8/7p/8/1N2QPP1/PPPPP2P/NB1RBK1R w HDhd - perft 1 36 perft 2 973 perft 3 35403 @@ -650,7 +650,7 @@ perft 5 37143354 perft 6 1124883780 id 72 -epd nnrbbkqr/2pppp1p/p7/6p1/1p2P3/4QPP1/PPPP3P/NNRBBK1R w HChc - 0 9 +epd nnrbbkqr/2pppp1p/p7/6p1/1p2P3/4QPP1/PPPP3P/NNRBBK1R w HChc - perft 1 36 perft 2 649 perft 3 22524 @@ -659,7 +659,7 @@ perft 5 16836636 perft 6 416139320 id 73 -epd nnrkbbqr/1p2pppp/p2p4/2p5/8/1N2P1P1/PPPP1P1P/1NKRBBQR w hc - 0 9 +epd nnrkbbqr/1p2pppp/p2p4/2p5/8/1N2P1P1/PPPP1P1P/1NKRBBQR w hc - perft 1 26 perft 2 672 perft 3 18136 @@ -668,7 +668,7 @@ perft 5 13342771 perft 6 363074681 id 74 -epd n1rkbqrb/pp1ppp2/2n3p1/2p4p/P5PP/1P6/2PPPP2/NNRKBQRB w GCgc - 0 9 +epd n1rkbqrb/pp1ppp2/2n3p1/2p4p/P5PP/1P6/2PPPP2/NNRKBQRB w GCgc - perft 1 24 perft 2 804 perft 3 20712 @@ -677,7 +677,7 @@ perft 5 18761475 perft 6 617932151 id 75 -epd nbkr1qbr/1pp1pppp/pn1p4/8/3P2P1/5R2/PPP1PP1P/NBN1KQBR w H - 2 9 +epd nbkr1qbr/1pp1pppp/pn1p4/8/3P2P1/5R2/PPP1PP1P/NBN1KQBR w H - perft 1 30 perft 2 627 perft 3 18669 @@ -686,7 +686,7 @@ perft 5 12815016 perft 6 312798696 id 76 -epd nnr1kqbr/pp1pp1p1/2p5/b4p1p/P7/1PNP4/2P1PPPP/N1RBKQBR w HChc - 1 9 +epd nnr1kqbr/pp1pp1p1/2p5/b4p1p/P7/1PNP4/2P1PPPP/N1RBKQBR w HChc - perft 1 12 perft 2 421 perft 3 6530 @@ -695,7 +695,7 @@ perft 5 4266410 perft 6 149176979 id 77 -epd n1rkqbbr/p1pp1pp1/np2p2p/8/8/N4PP1/PPPPP1BP/N1RKQ1BR w HChc - 0 9 +epd n1rkqbbr/p1pp1pp1/np2p2p/8/8/N4PP1/PPPPP1BP/N1RKQ1BR w HChc - perft 1 27 perft 2 670 perft 3 19119 @@ -704,7 +704,7 @@ perft 5 14708490 perft 6 397268628 id 78 -epd nnr1qrbb/p2kpppp/1p1p4/2p5/6P1/PP1P4/2P1PP1P/NNRKQRBB w FC - 0 9 +epd nnr1qrbb/p2kpppp/1p1p4/2p5/6P1/PP1P4/2P1PP1P/NNRKQRBB w FC - perft 1 27 perft 2 604 perft 3 17043 @@ -713,7 +713,7 @@ perft 5 11993332 perft 6 308518181 id 79 -epd bbnnrkrq/ppp1pp2/6p1/3p4/7p/7P/PPPPPPP1/BBNNRRKQ w ge - 0 9 +epd bbnnrkrq/ppp1pp2/6p1/3p4/7p/7P/PPPPPPP1/BBNNRRKQ w ge - perft 1 20 perft 2 559 perft 3 12242 @@ -722,7 +722,7 @@ perft 5 8427161 perft 6 252274233 id 80 -epd bnnbrkr1/ppp2p1p/5q2/3pp1p1/4P3/1N4P1/PPPPRP1P/BN1B1KRQ w Gge - 0 9 +epd bnnbrkr1/ppp2p1p/5q2/3pp1p1/4P3/1N4P1/PPPPRP1P/BN1B1KRQ w Gge - perft 1 26 perft 2 1036 perft 3 27228 @@ -731,7 +731,7 @@ perft 5 28286576 perft 6 1042120495 id 81 -epd bn1rkbrq/1pppppp1/p6p/1n6/3P4/6PP/PPPRPP2/BNN1KBRQ w Ggd - 2 9 +epd bn1rkbrq/1pppppp1/p6p/1n6/3P4/6PP/PPPRPP2/BNN1KBRQ w Ggd - perft 1 29 perft 2 633 perft 3 19278 @@ -740,7 +740,7 @@ perft 5 14333034 perft 6 361900466 id 82 -epd b1nrkrqb/1p1npppp/p2p4/2p5/5P2/4P2P/PPPP1RP1/BNNRK1QB w Dfd - 1 9 +epd b1nrkrqb/1p1npppp/p2p4/2p5/5P2/4P2P/PPPP1RP1/BNNRK1QB w Dfd - perft 1 25 perft 2 475 perft 3 12603 @@ -749,7 +749,7 @@ perft 5 7545536 perft 6 179579818 id 83 -epd 1bbnrkrq/ppppppp1/8/7p/1n4P1/1PN5/P1PPPP1P/NBBR1KRQ w Gge - 0 9 +epd 1bbnrkrq/ppppppp1/8/7p/1n4P1/1PN5/P1PPPP1P/NBBR1KRQ w Gge - perft 1 30 perft 2 803 perft 3 25473 @@ -758,7 +758,7 @@ perft 5 23443854 perft 6 686365049 id 84 -epd nnbbrkrq/2pp1pp1/1p5p/pP2p3/7P/N7/P1PPPPP1/N1BBRKRQ w GEge - 0 9 +epd nnbbrkrq/2pp1pp1/1p5p/pP2p3/7P/N7/P1PPPPP1/N1BBRKRQ w GEge - perft 1 18 perft 2 432 perft 3 9638 @@ -767,7 +767,7 @@ perft 5 6131124 perft 6 160393505 id 85 -epd nnbrkbrq/1pppp1p1/p7/7p/1P2Pp2/BN6/P1PP1PPP/1N1RKBRQ w GDgd - 0 9 +epd nnbrkbrq/1pppp1p1/p7/7p/1P2Pp2/BN6/P1PP1PPP/1N1RKBRQ w GDgd - perft 1 27 perft 2 482 perft 3 13441 @@ -776,7 +776,7 @@ perft 5 8084701 perft 6 193484216 id 86 -epd n1brkrqb/pppp3p/n3pp2/6p1/3P1P2/N1P5/PP2P1PP/N1BRKRQB w FDfd - 0 9 +epd n1brkrqb/pppp3p/n3pp2/6p1/3P1P2/N1P5/PP2P1PP/N1BRKRQB w FDfd - perft 1 28 perft 2 642 perft 3 19005 @@ -785,7 +785,7 @@ perft 5 14529434 perft 6 384837696 id 87 -epd nbnrbk2/p1pppp1p/1p3qr1/6p1/1B1P4/1N6/PPP1PPPP/1BNR1RKQ w d - 2 9 +epd nbnrbk2/p1pppp1p/1p3qr1/6p1/1B1P4/1N6/PPP1PPPP/1BNR1RKQ w d - perft 1 30 perft 2 796 perft 3 22780 @@ -794,7 +794,7 @@ perft 5 20120565 perft 6 641832725 id 88 -epd nnrbbrkq/1pp2ppp/3p4/p3p3/3P1P2/1P2P3/P1P3PP/NNRBBKRQ w GC - 1 9 +epd nnrbbrkq/1pp2ppp/3p4/p3p3/3P1P2/1P2P3/P1P3PP/NNRBBKRQ w GC - perft 1 31 perft 2 827 perft 3 24538 @@ -803,7 +803,7 @@ perft 5 19979594 perft 6 549437308 id 89 -epd nnrkbbrq/1pp2p1p/p2pp1p1/2P5/8/8/PP1PPPPP/NNRKBBRQ w Ggc - 0 9 +epd nnrkbbrq/1pp2p1p/p2pp1p1/2P5/8/8/PP1PPPPP/NNRKBBRQ w Ggc - perft 1 24 perft 2 762 perft 3 19283 @@ -812,7 +812,7 @@ perft 5 16838099 perft 6 555230555 id 90 -epd nnr1brqb/1ppkp1pp/8/p2p1p2/1P1P4/N1P5/P3PPPP/N1RKBRQB w FC - 1 9 +epd nnr1brqb/1ppkp1pp/8/p2p1p2/1P1P4/N1P5/P3PPPP/N1RKBRQB w FC - perft 1 23 perft 2 640 perft 3 15471 @@ -821,7 +821,7 @@ perft 5 11343507 perft 6 334123513 id 91 -epd nbnrkrbq/2ppp2p/p4p2/1P4p1/4PP2/8/1PPP2PP/NBNRKRBQ w FDfd - 0 9 +epd nbnrkrbq/2ppp2p/p4p2/1P4p1/4PP2/8/1PPP2PP/NBNRKRBQ w FDfd - perft 1 31 perft 2 826 perft 3 26137 @@ -830,7 +830,7 @@ perft 5 23555139 perft 6 686250413 id 92 -epd 1nrbkr1q/1pppp1pp/1n6/p4p2/N1b4P/8/PPPPPPPB/N1RBKR1Q w FCfc - 2 9 +epd 1nrbkr1q/1pppp1pp/1n6/p4p2/N1b4P/8/PPPPPPPB/N1RBKR1Q w FCfc - perft 1 27 perft 2 862 perft 3 24141 @@ -839,7 +839,7 @@ perft 5 22027695 perft 6 696353497 id 93 -epd nnrkrbbq/pppp2pp/8/4pp2/4P3/P7/1PPPBPPP/NNKRR1BQ w c - 0 9 +epd nnrkrbbq/pppp2pp/8/4pp2/4P3/P7/1PPPBPPP/NNKRR1BQ w c - perft 1 25 perft 2 792 perft 3 19883 @@ -848,7 +848,7 @@ perft 5 16473376 perft 6 532214177 id 94 -epd n1rk1qbb/pppprpp1/2n4p/4p3/2PP3P/8/PP2PPP1/NNRKRQBB w ECc - 1 9 +epd n1rk1qbb/pppprpp1/2n4p/4p3/2PP3P/8/PP2PPP1/NNRKRQBB w ECc - perft 1 25 perft 2 622 perft 3 16031 @@ -857,7 +857,7 @@ perft 5 11420973 perft 6 321855685 id 95 -epd bbq1rnkr/pnp1pp1p/1p1p4/6p1/2P5/2Q1P2P/PP1P1PP1/BB1NRNKR w HEhe - 2 9 +epd bbq1rnkr/pnp1pp1p/1p1p4/6p1/2P5/2Q1P2P/PP1P1PP1/BB1NRNKR w HEhe - perft 1 36 perft 2 870 perft 3 30516 @@ -866,7 +866,7 @@ perft 5 28127620 perft 6 799738334 id 96 -epd bq1brnkr/1p1ppp1p/1np5/p5p1/8/1N5P/PPPPPPP1/BQ1BRNKR w HEhe - 0 9 +epd bq1brnkr/1p1ppp1p/1np5/p5p1/8/1N5P/PPPPPPP1/BQ1BRNKR w HEhe - perft 1 22 perft 2 588 perft 3 13524 @@ -875,7 +875,7 @@ perft 5 9359618 perft 6 273795898 id 97 -epd bq1rn1kr/1pppppbp/Nn4p1/8/8/P7/1PPPPPPP/BQ1RNBKR w HDhd - 1 9 +epd bq1rn1kr/1pppppbp/Nn4p1/8/8/P7/1PPPPPPP/BQ1RNBKR w HDhd - perft 1 24 perft 2 711 perft 3 18197 @@ -884,7 +884,7 @@ perft 5 14692779 perft 6 445827351 id 98 -epd bqnr1kr1/pppppp1p/6p1/5n2/4B3/3N2PP/PbPPPP2/BQNR1KR1 w GDgd - 2 9 +epd bqnr1kr1/pppppp1p/6p1/5n2/4B3/3N2PP/PbPPPP2/BQNR1KR1 w GDgd - perft 1 31 perft 2 1132 perft 3 36559 @@ -893,7 +893,7 @@ perft 5 43256823 perft 6 1456721391 id 99 -epd qbb1rnkr/ppp3pp/4n3/3ppp2/1P3PP1/8/P1PPPN1P/QBB1RNKR w HEhe - 0 9 +epd qbb1rnkr/ppp3pp/4n3/3ppp2/1P3PP1/8/P1PPPN1P/QBB1RNKR w HEhe - perft 1 28 perft 2 696 perft 3 20502 @@ -902,7 +902,7 @@ perft 5 16492398 perft 6 456983120 id 100 -epd qnbbr1kr/pp1ppp1p/4n3/6p1/2p3P1/2PP1P2/PP2P2P/QNBBRNKR w HEhe - 0 9 +epd qnbbr1kr/pp1ppp1p/4n3/6p1/2p3P1/2PP1P2/PP2P2P/QNBBRNKR w HEhe - perft 1 25 perft 2 655 perft 3 16520 @@ -911,7 +911,7 @@ perft 5 11767038 perft 6 335414976 id 101 -epd 1nbrnbkr/p1ppp1pp/1p6/5p2/4q1PP/3P4/PPP1PP2/QNBRNBKR w HDhd - 1 9 +epd 1nbrnbkr/p1ppp1pp/1p6/5p2/4q1PP/3P4/PPP1PP2/QNBRNBKR w HDhd - perft 1 30 perft 2 1162 perft 3 33199 @@ -920,7 +920,7 @@ perft 5 36048727 perft 6 1290346802 id 102 -epd q1brnkrb/p1pppppp/n7/1p6/P7/3P1P2/QPP1P1PP/1NBRNKRB w GDgd - 0 9 +epd q1brnkrb/p1pppppp/n7/1p6/P7/3P1P2/QPP1P1PP/1NBRNKRB w GDgd - perft 1 32 perft 2 827 perft 3 26106 @@ -929,7 +929,7 @@ perft 5 23143989 perft 6 673147648 id 103 -epd qbnrb1kr/ppp1pp1p/3p4/2n3p1/1P6/6N1/P1PPPPPP/QBNRB1KR w HDhd - 2 9 +epd qbnrb1kr/ppp1pp1p/3p4/2n3p1/1P6/6N1/P1PPPPPP/QBNRB1KR w HDhd - perft 1 29 perft 2 751 perft 3 23132 @@ -938,7 +938,7 @@ perft 5 19555214 perft 6 530475036 id 104 -epd q1rbbnkr/pppp1p2/2n3pp/2P1p3/3P4/8/PP1NPPPP/Q1RBBNKR w HChc - 2 9 +epd q1rbbnkr/pppp1p2/2n3pp/2P1p3/3P4/8/PP1NPPPP/Q1RBBNKR w HChc - perft 1 29 perft 2 806 perft 3 24540 @@ -947,7 +947,7 @@ perft 5 21694330 perft 6 619907316 id 105 -epd q1r1bbkr/pnpp1ppp/2n1p3/1p6/2P2P2/2N1N3/PP1PP1PP/Q1R1BBKR w HChc - 2 9 +epd q1r1bbkr/pnpp1ppp/2n1p3/1p6/2P2P2/2N1N3/PP1PP1PP/Q1R1BBKR w HChc - perft 1 32 perft 2 1017 perft 3 32098 @@ -956,7 +956,7 @@ perft 5 31204371 perft 6 958455898 id 106 -epd 2rnbkrb/pqppppp1/1pn5/7p/2P5/P1R5/QP1PPPPP/1N1NBKRB w Ggc - 4 9 +epd 2rnbkrb/pqppppp1/1pn5/7p/2P5/P1R5/QP1PPPPP/1N1NBKRB w Ggc - perft 1 26 perft 2 625 perft 3 16506 @@ -965,7 +965,7 @@ perft 5 11856964 perft 6 336672890 id 107 -epd qbnr1kbr/p2ppppp/2p5/1p6/4n2P/P4N2/1PPP1PP1/QBNR1KBR w HDhd - 0 9 +epd qbnr1kbr/p2ppppp/2p5/1p6/4n2P/P4N2/1PPP1PP1/QBNR1KBR w HDhd - perft 1 27 perft 2 885 perft 3 23828 @@ -974,7 +974,7 @@ perft 5 21855658 perft 6 706272554 id 108 -epd qnrbnk1r/pp1pp2p/5p2/2pbP1p1/3P4/1P6/P1P2PPP/QNRBNKBR w HChc - 0 9 +epd qnrbnk1r/pp1pp2p/5p2/2pbP1p1/3P4/1P6/P1P2PPP/QNRBNKBR w HChc - perft 1 26 perft 2 954 perft 3 24832 @@ -983,7 +983,7 @@ perft 5 24415089 perft 6 866744329 id 109 -epd qnrnk1br/p1p2ppp/8/1pbpp3/8/PP2N3/1QPPPPPP/1NR1KBBR w HChc - 0 9 +epd qnrnk1br/p1p2ppp/8/1pbpp3/8/PP2N3/1QPPPPPP/1NR1KBBR w HChc - perft 1 26 perft 2 783 perft 3 20828 @@ -992,7 +992,7 @@ perft 5 17477825 perft 6 539674275 id 110 -epd qnrnkrbb/Bpppp2p/6p1/5p2/5P2/3PP3/PPP3PP/QNRNKR1B w FCfc - 1 9 +epd qnrnkrbb/Bpppp2p/6p1/5p2/5P2/3PP3/PPP3PP/QNRNKR1B w FCfc - perft 1 28 perft 2 908 perft 3 25730 @@ -1001,7 +1001,7 @@ perft 5 25251641 perft 6 869525254 id 111 -epd bbnqrn1r/ppppp2k/5p2/6pp/7P/1QP5/PP1PPPP1/B1N1RNKR w HE - 0 9 +epd bbnqrn1r/ppppp2k/5p2/6pp/7P/1QP5/PP1PPPP1/B1N1RNKR w HE - perft 1 33 perft 2 643 perft 3 21790 @@ -1010,7 +1010,7 @@ perft 5 16693640 perft 6 410115900 id 112 -epd b1qbrnkr/ppp1pp2/2np4/6pp/4P3/2N4P/PPPP1PP1/BQ1BRNKR w HEhe - 0 9 +epd b1qbrnkr/ppp1pp2/2np4/6pp/4P3/2N4P/PPPP1PP1/BQ1BRNKR w HEhe - perft 1 28 perft 2 837 perft 3 24253 @@ -1019,7 +1019,7 @@ perft 5 22197063 perft 6 696399065 id 113 -epd bnqr1bkr/pp1ppppp/2p5/4N3/5P2/P7/1PPPPnPP/BNQR1BKR w HDhd - 3 9 +epd bnqr1bkr/pp1ppppp/2p5/4N3/5P2/P7/1PPPPnPP/BNQR1BKR w HDhd - perft 1 25 perft 2 579 perft 3 13909 @@ -1028,7 +1028,7 @@ perft 5 8601011 perft 6 225530258 id 114 -epd b1qr1krb/pp1ppppp/n2n4/8/2p5/2P3P1/PP1PPP1P/BNQRNKRB w GDgd - 0 9 +epd b1qr1krb/pp1ppppp/n2n4/8/2p5/2P3P1/PP1PPP1P/BNQRNKRB w GDgd - perft 1 28 perft 2 707 perft 3 19721 @@ -1037,7 +1037,7 @@ perft 5 15583376 perft 6 468399900 id 115 -epd nbbqr1kr/1pppp1pp/8/p1n2p2/4P3/PN6/1PPPQPPP/1BB1RNKR w HEhe - 0 9 +epd nbbqr1kr/1pppp1pp/8/p1n2p2/4P3/PN6/1PPPQPPP/1BB1RNKR w HEhe - perft 1 30 perft 2 745 perft 3 23416 @@ -1046,7 +1046,7 @@ perft 5 19478789 perft 6 515473678 id 116 -epd nqbbrn1r/p1pppp1k/1p4p1/7p/4P3/1R3B2/PPPP1PPP/NQB2NKR w H - 0 9 +epd nqbbrn1r/p1pppp1k/1p4p1/7p/4P3/1R3B2/PPPP1PPP/NQB2NKR w H - perft 1 24 perft 2 504 perft 3 13512 @@ -1055,7 +1055,7 @@ perft 5 9002073 perft 6 228726497 id 117 -epd nqbr1bkr/p1p1ppp1/1p1n4/3pN2p/1P6/8/P1PPPPPP/NQBR1BKR w HDhd - 0 9 +epd nqbr1bkr/p1p1ppp1/1p1n4/3pN2p/1P6/8/P1PPPPPP/NQBR1BKR w HDhd - perft 1 29 perft 2 898 perft 3 26532 @@ -1064,7 +1064,7 @@ perft 5 24703467 perft 6 757166494 id 118 -epd nqbrn1rb/pppp1kp1/5p1p/4p3/P4B2/3P2P1/1PP1PP1P/NQ1RNKRB w GD - 0 9 +epd nqbrn1rb/pppp1kp1/5p1p/4p3/P4B2/3P2P1/1PP1PP1P/NQ1RNKRB w GD - perft 1 34 perft 2 671 perft 3 22332 @@ -1073,7 +1073,7 @@ perft 5 15556806 perft 6 353235120 id 119 -epd nb1r1nkr/ppp1ppp1/2bp4/7p/3P2qP/P6R/1PP1PPP1/NBQRBNK1 w Dhd - 1 9 +epd nb1r1nkr/ppp1ppp1/2bp4/7p/3P2qP/P6R/1PP1PPP1/NBQRBNK1 w Dhd - perft 1 38 perft 2 1691 perft 3 60060 @@ -1082,7 +1082,7 @@ perft 5 88557078 perft 6 3589649998 id 120 -epd n1rbbnkr/1p1pp1pp/p7/2p1qp2/1B3P2/3P4/PPP1P1PP/NQRB1NKR w HChc - 0 9 +epd n1rbbnkr/1p1pp1pp/p7/2p1qp2/1B3P2/3P4/PPP1P1PP/NQRB1NKR w HChc - perft 1 24 perft 2 913 perft 3 21595 @@ -1091,7 +1091,7 @@ perft 5 19866918 perft 6 737239330 id 121 -epd nqrnbbkr/p2p1p1p/1pp5/1B2p1p1/1P3P2/4P3/P1PP2PP/NQRNB1KR w HChc - 0 9 +epd nqrnbbkr/p2p1p1p/1pp5/1B2p1p1/1P3P2/4P3/P1PP2PP/NQRNB1KR w HChc - perft 1 33 perft 2 913 perft 3 30159 @@ -1100,7 +1100,7 @@ perft 5 28053260 perft 6 804687975 id 122 -epd nqr1bkrb/ppp1pp2/2np2p1/P6p/8/2P4P/1P1PPPP1/NQRNBKRB w GCgc - 0 9 +epd nqr1bkrb/ppp1pp2/2np2p1/P6p/8/2P4P/1P1PPPP1/NQRNBKRB w GCgc - perft 1 24 perft 2 623 perft 3 16569 @@ -1109,7 +1109,7 @@ perft 5 12681936 perft 6 351623879 id 123 -epd nb1rnkbr/pqppppp1/1p5p/8/1PP4P/8/P2PPPP1/NBQRNKBR w HDhd - 1 9 +epd nb1rnkbr/pqppppp1/1p5p/8/1PP4P/8/P2PPPP1/NBQRNKBR w HDhd - perft 1 31 perft 2 798 perft 3 24862 @@ -1118,7 +1118,7 @@ perft 5 22616076 perft 6 666227466 id 124 -epd nqrbnkbr/2p1p1pp/3p4/pp3p2/6PP/3P1N2/PPP1PP2/NQRB1KBR w HChc - 0 9 +epd nqrbnkbr/2p1p1pp/3p4/pp3p2/6PP/3P1N2/PPP1PP2/NQRB1KBR w HChc - perft 1 24 perft 2 590 perft 3 14409 @@ -1127,7 +1127,7 @@ perft 5 9698432 perft 6 274064911 id 125 -epd nqrnkbbr/pp1p1p1p/4p1p1/1p6/8/5P1P/P1PPP1P1/NQRNKBBR w HChc - 0 9 +epd nqrnkbbr/pp1p1p1p/4p1p1/1p6/8/5P1P/P1PPP1P1/NQRNKBBR w HChc - perft 1 30 perft 2 1032 perft 3 31481 @@ -1136,7 +1136,7 @@ perft 5 34914919 perft 6 1233362066 id 126 -epd nqrnkrbb/p2ppppp/1p6/2p5/2P3P1/5P2/PP1PPN1P/NQR1KRBB w FCfc - 1 9 +epd nqrnkrbb/p2ppppp/1p6/2p5/2P3P1/5P2/PP1PPN1P/NQR1KRBB w FCfc - perft 1 30 perft 2 775 perft 3 23958 @@ -1145,7 +1145,7 @@ perft 5 21141738 perft 6 621142773 id 127 -epd bbnrqrk1/pp2pppp/4n3/2pp4/P7/1N5P/BPPPPPP1/B2RQNKR w HD - 2 9 +epd bbnrqrk1/pp2pppp/4n3/2pp4/P7/1N5P/BPPPPPP1/B2RQNKR w HD - perft 1 23 perft 2 708 perft 3 17164 @@ -1154,7 +1154,7 @@ perft 5 14343443 perft 6 481405144 id 128 -epd bnr1qnkr/p1pp1p1p/1p4p1/4p1b1/2P1P3/1P6/PB1P1PPP/1NRBQNKR w HChc - 1 9 +epd bnr1qnkr/p1pp1p1p/1p4p1/4p1b1/2P1P3/1P6/PB1P1PPP/1NRBQNKR w HChc - perft 1 30 perft 2 931 perft 3 29249 @@ -1163,7 +1163,7 @@ perft 5 30026687 perft 6 968109774 id 129 -epd b1rqnbkr/ppp1ppp1/3p3p/2n5/P3P3/2NP4/1PP2PPP/B1RQNBKR w HChc - 0 9 +epd b1rqnbkr/ppp1ppp1/3p3p/2n5/P3P3/2NP4/1PP2PPP/B1RQNBKR w HChc - perft 1 24 perft 2 596 perft 3 15533 @@ -1172,7 +1172,7 @@ perft 5 11099382 perft 6 294180723 id 130 -epd bnrqnr1b/pp1pkppp/2p1p3/P7/2P5/7P/1P1PPPP1/BNRQNKRB w GC - 0 9 +epd bnrqnr1b/pp1pkppp/2p1p3/P7/2P5/7P/1P1PPPP1/BNRQNKRB w GC - perft 1 24 perft 2 572 perft 3 15293 @@ -1181,7 +1181,7 @@ perft 5 11208688 perft 6 302955778 id 131 -epd n1brq1kr/bppppppp/p7/8/4P1Pn/8/PPPP1P2/NBBRQNKR w HDhd - 0 9 +epd n1brq1kr/bppppppp/p7/8/4P1Pn/8/PPPP1P2/NBBRQNKR w HDhd - perft 1 20 perft 2 570 perft 3 13139 @@ -1190,7 +1190,7 @@ perft 5 9919113 perft 6 284592289 id 132 -epd 1rbbqnkr/ppn1ppp1/3p3p/2p5/3P4/1N4P1/PPPBPP1P/1R1BQNKR w HBhb - 0 9 +epd 1rbbqnkr/ppn1ppp1/3p3p/2p5/3P4/1N4P1/PPPBPP1P/1R1BQNKR w HBhb - perft 1 29 perft 2 1009 perft 3 29547 @@ -1199,7 +1199,7 @@ perft 5 31059587 perft 6 1111986835 id 133 -epd nrbq2kr/ppppppb1/5n1p/5Pp1/8/P5P1/1PPPP2P/NRBQNBKR w HBhb - 1 9 +epd nrbq2kr/ppppppb1/5n1p/5Pp1/8/P5P1/1PPPP2P/NRBQNBKR w HBhb - perft 1 20 perft 2 520 perft 3 11745 @@ -1208,7 +1208,7 @@ perft 5 7809837 perft 6 216997152 id 134 -epd nrb1nkrb/pp3ppp/1qBpp3/2p5/8/P5P1/1PPPPP1P/NRBQNKR1 w GBgb - 2 9 +epd nrb1nkrb/pp3ppp/1qBpp3/2p5/8/P5P1/1PPPPP1P/NRBQNKR1 w GBgb - perft 1 32 perft 2 850 perft 3 25642 @@ -1217,7 +1217,7 @@ perft 5 21981567 perft 6 664886187 id 135 -epd 1br1bnkr/ppqppp1p/1np3p1/8/1PP4P/4N3/P2PPPP1/NBRQB1KR w HChc - 1 9 +epd 1br1bnkr/ppqppp1p/1np3p1/8/1PP4P/4N3/P2PPPP1/NBRQB1KR w HChc - perft 1 32 perft 2 798 perft 3 24765 @@ -1226,7 +1226,7 @@ perft 5 22076141 perft 6 670296871 id 136 -epd nrqbb1kr/1p1pp1pp/2p3n1/p4p2/3PP3/P5N1/1PP2PPP/NRQBB1KR w HBhb - 0 9 +epd nrqbb1kr/1p1pp1pp/2p3n1/p4p2/3PP3/P5N1/1PP2PPP/NRQBB1KR w HBhb - perft 1 32 perft 2 791 perft 3 26213 @@ -1235,7 +1235,7 @@ perft 5 23239122 perft 6 634260266 id 137 -epd nrqn1bkr/ppppp1pp/4b3/8/4P1p1/5P2/PPPP3P/NRQNBBKR w HBhb - 0 9 +epd nrqn1bkr/ppppp1pp/4b3/8/4P1p1/5P2/PPPP3P/NRQNBBKR w HBhb - perft 1 29 perft 2 687 perft 3 20223 @@ -1244,7 +1244,7 @@ perft 5 15236287 perft 6 398759980 id 138 -epd nrqnbrkb/pppp1p2/4p2p/3B2p1/8/1P4P1/PQPPPP1P/NR1NBKR1 w GB - 0 9 +epd nrqnbrkb/pppp1p2/4p2p/3B2p1/8/1P4P1/PQPPPP1P/NR1NBKR1 w GB - perft 1 37 perft 2 764 perft 3 27073 @@ -1253,7 +1253,7 @@ perft 5 21284835 perft 6 514864869 id 139 -epd nbrq1kbr/Bp3ppp/2pnp3/3p4/5P2/2P4P/PP1PP1P1/NBRQNK1R w HChc - 0 9 +epd nbrq1kbr/Bp3ppp/2pnp3/3p4/5P2/2P4P/PP1PP1P1/NBRQNK1R w HChc - perft 1 40 perft 2 1271 perft 3 48022 @@ -1262,7 +1262,7 @@ perft 5 56588117 perft 6 1850696281 id 140 -epd nrqbnkbr/1p2ppp1/p1p4p/3p4/1P6/8/PQPPPPPP/1RNBNKBR w HBhb - 0 9 +epd nrqbnkbr/1p2ppp1/p1p4p/3p4/1P6/8/PQPPPPPP/1RNBNKBR w HBhb - perft 1 28 perft 2 757 perft 3 23135 @@ -1271,7 +1271,7 @@ perft 5 21427496 perft 6 650939962 id 141 -epd nrqn1bbr/2ppkppp/4p3/pB6/8/2P1P3/PP1P1PPP/NRQNK1BR w HB - 1 9 +epd nrqn1bbr/2ppkppp/4p3/pB6/8/2P1P3/PP1P1PPP/NRQNK1BR w HB - perft 1 27 perft 2 642 perft 3 17096 @@ -1280,7 +1280,7 @@ perft 5 11872805 perft 6 327545120 id 142 -epd nrqnkrb1/p1ppp2p/1p4p1/4bp2/4PP1P/4N3/PPPP2P1/NRQ1KRBB w FBfb - 1 9 +epd nrqnkrb1/p1ppp2p/1p4p1/4bp2/4PP1P/4N3/PPPP2P1/NRQ1KRBB w FBfb - perft 1 27 perft 2 958 perft 3 27397 @@ -1289,7 +1289,7 @@ perft 5 28520172 perft 6 995356563 id 143 -epd 1bnrnqkr/pbpp2pp/8/1p2pp2/P6P/3P1N2/1PP1PPP1/BBNR1QKR w HDhd - 0 9 +epd 1bnrnqkr/pbpp2pp/8/1p2pp2/P6P/3P1N2/1PP1PPP1/BBNR1QKR w HDhd - perft 1 27 perft 2 859 perft 3 23475 @@ -1298,7 +1298,7 @@ perft 5 21581178 perft 6 732696327 id 144 -epd b1rbnqkr/1pp1ppp1/2n4p/p2p4/5P2/1PBP4/P1P1P1PP/1NRBNQKR w HChc - 0 9 +epd b1rbnqkr/1pp1ppp1/2n4p/p2p4/5P2/1PBP4/P1P1P1PP/1NRBNQKR w HChc - perft 1 26 perft 2 545 perft 3 14817 @@ -1307,7 +1307,7 @@ perft 5 9537260 perft 6 233549184 id 145 -epd 1nrnqbkr/p1pppppp/1p6/8/2b2P2/P1N5/1PP1P1PP/BNR1QBKR w HChc - 2 9 +epd 1nrnqbkr/p1pppppp/1p6/8/2b2P2/P1N5/1PP1P1PP/BNR1QBKR w HChc - perft 1 24 perft 2 668 perft 3 17716 @@ -1316,7 +1316,7 @@ perft 5 14216070 perft 6 406225409 id 146 -epd 1nrnqkrb/2ppp1pp/p7/1p3p2/5P2/N5K1/PPPPP2P/B1RNQ1RB w gc - 0 9 +epd 1nrnqkrb/2ppp1pp/p7/1p3p2/5P2/N5K1/PPPPP2P/B1RNQ1RB w gc - perft 1 33 perft 2 725 perft 3 23572 @@ -1325,7 +1325,7 @@ perft 5 18547476 perft 6 471443091 id 147 -epd nbbr1qkr/p1pppppp/8/1p1n4/3P4/1N3PP1/PPP1P2P/1BBRNQKR w HDhd - 1 9 +epd nbbr1qkr/p1pppppp/8/1p1n4/3P4/1N3PP1/PPP1P2P/1BBRNQKR w HDhd - perft 1 28 perft 2 698 perft 3 20527 @@ -1334,7 +1334,7 @@ perft 5 16555068 perft 6 458045505 id 148 -epd 1rbbnqkr/1pnppp1p/p5p1/2p5/2P4P/5P2/PP1PP1PR/NRBBNQK1 w Bhb - 1 9 +epd 1rbbnqkr/1pnppp1p/p5p1/2p5/2P4P/5P2/PP1PP1PR/NRBBNQK1 w Bhb - perft 1 24 perft 2 554 perft 3 14221 @@ -1343,7 +1343,7 @@ perft 5 9863080 perft 6 269284081 id 149 -epd nrb1qbkr/2pppppp/2n5/p7/2p5/4P3/PPNP1PPP/1RBNQBKR w HBhb - 0 9 +epd nrb1qbkr/2pppppp/2n5/p7/2p5/4P3/PPNP1PPP/1RBNQBKR w HBhb - perft 1 23 perft 2 618 perft 3 15572 @@ -1352,7 +1352,7 @@ perft 5 12044358 perft 6 360311412 id 150 -epd nrb1qkrb/2ppppp1/p3n3/1p1B3p/2P5/6P1/PP1PPPRP/NRBNQK2 w Bgb - 2 9 +epd nrb1qkrb/2ppppp1/p3n3/1p1B3p/2P5/6P1/PP1PPPRP/NRBNQK2 w Bgb - perft 1 27 perft 2 593 perft 3 16770 @@ -1361,7 +1361,7 @@ perft 5 11806808 perft 6 303338935 id 151 -epd nbrn1qkr/ppp1pp2/3p2p1/3Q3P/b7/8/PPPPPP1P/NBRNB1KR w HChc - 2 9 +epd nbrn1qkr/ppp1pp2/3p2p1/3Q3P/b7/8/PPPPPP1P/NBRNB1KR w HChc - perft 1 39 perft 2 1056 perft 3 40157 @@ -1370,7 +1370,7 @@ perft 5 42201531 perft 6 1239888683 id 152 -epd nr1bbqkr/pp1pp2p/1n3pp1/2p5/8/1P4P1/P1PPPPQP/NRNBBK1R w hb - 0 9 +epd nr1bbqkr/pp1pp2p/1n3pp1/2p5/8/1P4P1/P1PPPPQP/NRNBBK1R w hb - perft 1 25 perft 2 585 perft 3 15719 @@ -1379,7 +1379,7 @@ perft 5 11582539 perft 6 320997679 id 153 -epd nr2bbkr/ppp1pppp/1n1p4/8/6PP/1NP4q/PP1PPP2/1RNQBBKR w HBhb - 1 9 +epd nr2bbkr/ppp1pppp/1n1p4/8/6PP/1NP4q/PP1PPP2/1RNQBBKR w HBhb - perft 1 22 perft 2 742 perft 3 15984 @@ -1388,7 +1388,7 @@ perft 5 13287051 perft 6 457010195 id 154 -epd 1rnqbkrb/ppp1p1p1/1n3p2/3p3p/P6P/4P3/1PPP1PP1/NRNQBRKB w gb - 0 9 +epd 1rnqbkrb/ppp1p1p1/1n3p2/3p3p/P6P/4P3/1PPP1PP1/NRNQBRKB w gb - perft 1 22 perft 2 574 perft 3 14044 @@ -1397,7 +1397,7 @@ perft 5 9968830 perft 6 281344367 id 155 -epd nb1rqkbr/1pppp1pp/4n3/p4p2/6PP/5P2/PPPPPN2/NBR1QKBR w HCh - 0 9 +epd nb1rqkbr/1pppp1pp/4n3/p4p2/6PP/5P2/PPPPPN2/NBR1QKBR w HCh - perft 1 25 perft 2 621 perft 3 16789 @@ -1406,7 +1406,7 @@ perft 5 13378840 perft 6 396575613 id 156 -epd nrnbqkbr/2pp2pp/4pp2/pp6/8/1P3P2/P1PPPBPP/NRNBQ1KR w hb - 0 9 +epd nrnbqkbr/2pp2pp/4pp2/pp6/8/1P3P2/P1PPPBPP/NRNBQ1KR w hb - perft 1 25 perft 2 656 perft 3 16951 @@ -1415,7 +1415,7 @@ perft 5 12525939 perft 6 358763789 id 157 -epd nrnqkbbr/ppppp1p1/7p/5p2/8/P4PP1/NPPPP2P/NR1QKBBR w HBhb - 0 9 +epd nrnqkbbr/ppppp1p1/7p/5p2/8/P4PP1/NPPPP2P/NR1QKBBR w HBhb - perft 1 28 perft 2 723 perft 3 20621 @@ -1424,7 +1424,7 @@ perft 5 15952533 perft 6 439046803 id 158 -epd 1rnqkr1b/ppppp2p/1n3pp1/8/2P3P1/Pb1N4/1P1PPP1P/NR1QKRBB w FBfb - 0 9 +epd 1rnqkr1b/ppppp2p/1n3pp1/8/2P3P1/Pb1N4/1P1PPP1P/NR1QKRBB w FBfb - perft 1 26 perft 2 713 perft 3 19671 @@ -1433,7 +1433,7 @@ perft 5 15865528 perft 6 454532806 id 159 -epd bbnrnkqr/1pppp1pp/5p2/p7/7P/1P6/PBPPPPPR/1BNRNKQ1 w D - 2 9 +epd bbnrnkqr/1pppp1pp/5p2/p7/7P/1P6/PBPPPPPR/1BNRNKQ1 w D - perft 1 26 perft 2 649 perft 3 17834 @@ -1442,7 +1442,7 @@ perft 5 14375839 perft 6 435585252 id 160 -epd bnrbk1qr/1ppp1ppp/p2np3/8/P7/2N2P2/1PPPP1PP/B1RBNKQR w HC - 0 9 +epd bnrbk1qr/1ppp1ppp/p2np3/8/P7/2N2P2/1PPPP1PP/B1RBNKQR w HC - perft 1 26 perft 2 621 perft 3 17569 @@ -1451,7 +1451,7 @@ perft 5 13514201 perft 6 364421088 id 161 -epd br1nkbqr/ppppppp1/8/n6p/8/N1P2PP1/PP1PP2P/B1RNKBQR w HCh - 1 9 +epd br1nkbqr/ppppppp1/8/n6p/8/N1P2PP1/PP1PP2P/B1RNKBQR w HCh - perft 1 29 perft 2 664 perft 3 20182 @@ -1460,7 +1460,7 @@ perft 5 16125924 perft 6 442508159 id 162 -epd bnr1kqrb/pp1pppp1/2n5/2p5/1P4Pp/4N3/P1PPPP1P/BNKR1QRB w gc - 0 9 +epd bnr1kqrb/pp1pppp1/2n5/2p5/1P4Pp/4N3/P1PPPP1P/BNKR1QRB w gc - perft 1 36 perft 2 888 perft 3 31630 @@ -1469,7 +1469,7 @@ perft 5 27792175 perft 6 719015345 id 163 -epd 1bbrnkqr/pp1p1ppp/2p1p3/1n6/5P2/3Q4/PPPPP1PP/NBBRNK1R w HDhd - 2 9 +epd 1bbrnkqr/pp1p1ppp/2p1p3/1n6/5P2/3Q4/PPPPP1PP/NBBRNK1R w HDhd - perft 1 36 perft 2 891 perft 3 31075 @@ -1478,7 +1478,7 @@ perft 5 26998966 perft 6 702903862 id 164 -epd nrbbnk1r/pp2pppq/8/2pp3p/3P2P1/1N6/PPP1PP1P/1RBBNKQR w HBhb - 0 9 +epd nrbbnk1r/pp2pppq/8/2pp3p/3P2P1/1N6/PPP1PP1P/1RBBNKQR w HBhb - perft 1 29 perft 2 1036 perft 3 31344 @@ -1487,7 +1487,7 @@ perft 5 35627310 perft 6 1310683359 id 165 -epd nr1nkbqr/ppp3pp/5p2/3pp3/6b1/3PP3/PPP2PPP/NRBNKBQR w hb - 0 9 +epd nr1nkbqr/ppp3pp/5p2/3pp3/6b1/3PP3/PPP2PPP/NRBNKBQR w hb - perft 1 18 perft 2 664 perft 3 13306 @@ -1496,7 +1496,7 @@ perft 5 10658989 perft 6 386307449 id 166 -epd nrbnk1rb/ppp1pq1p/3p4/5pp1/2P1P3/1N6/PP1PKPPP/1RBN1QRB w gb - 2 9 +epd nrbnk1rb/ppp1pq1p/3p4/5pp1/2P1P3/1N6/PP1PKPPP/1RBN1QRB w gb - perft 1 25 perft 2 966 perft 3 24026 @@ -1505,7 +1505,7 @@ perft 5 23957242 perft 6 913710194 id 167 -epd 1brnbkqr/pppppp2/6p1/7p/1Pn5/P1NP4/2P1PPPP/NBR1BKQR w HChc - 0 9 +epd 1brnbkqr/pppppp2/6p1/7p/1Pn5/P1NP4/2P1PPPP/NBR1BKQR w HChc - perft 1 22 perft 2 627 perft 3 13760 @@ -1514,7 +1514,7 @@ perft 5 9627826 perft 6 285900573 id 168 -epd nrnbbk1r/p1pppppq/8/7p/1p6/P5PP/1PPPPPQ1/NRNBBK1R w HBhb - 2 9 +epd nrnbbk1r/p1pppppq/8/7p/1p6/P5PP/1PPPPPQ1/NRNBBK1R w HBhb - perft 1 29 perft 2 888 perft 3 26742 @@ -1523,7 +1523,7 @@ perft 5 27229468 perft 6 930799376 id 169 -epd n1nkb1qr/prppppbp/6p1/1p6/2P2P2/P7/1P1PP1PP/NRNKBBQR w HBh - 1 9 +epd n1nkb1qr/prppppbp/6p1/1p6/2P2P2/P7/1P1PP1PP/NRNKBBQR w HBh - perft 1 29 perft 2 804 perft 3 24701 @@ -1532,7 +1532,7 @@ perft 5 21952444 perft 6 623156747 id 170 -epd nr2bqrb/ppkpp1pp/1np5/5p1P/5P2/2P5/PP1PP1P1/NRNKBQRB w GB - 0 9 +epd nr2bqrb/ppkpp1pp/1np5/5p1P/5P2/2P5/PP1PP1P1/NRNKBQRB w GB - perft 1 22 perft 2 530 perft 3 13055 @@ -1541,7 +1541,7 @@ perft 5 9244693 perft 6 264088392 id 171 -epd nbr1kqbr/p3pppp/2ppn3/1p4P1/4P3/1P6/P1PP1P1P/NBRNKQBR w HChc - 1 9 +epd nbr1kqbr/p3pppp/2ppn3/1p4P1/4P3/1P6/P1PP1P1P/NBRNKQBR w HChc - perft 1 23 perft 2 555 perft 3 14291 @@ -1550,7 +1550,7 @@ perft 5 9692630 perft 6 247479180 id 172 -epd nr1bkqbr/1p1pp1pp/pnp2p2/8/6P1/P1PP4/1P2PP1P/NRNBKQBR w HBhb - 0 9 +epd nr1bkqbr/1p1pp1pp/pnp2p2/8/6P1/P1PP4/1P2PP1P/NRNBKQBR w HBhb - perft 1 22 perft 2 565 perft 3 13343 @@ -1559,7 +1559,7 @@ perft 5 9305533 perft 6 268612479 id 173 -epd nr1kqbbr/np2pppp/p1p5/1B1p1P2/8/4P3/PPPP2PP/NRNKQ1BR w HBhb - 0 9 +epd nr1kqbbr/np2pppp/p1p5/1B1p1P2/8/4P3/PPPP2PP/NRNKQ1BR w HBhb - perft 1 32 perft 2 730 perft 3 23391 @@ -1568,7 +1568,7 @@ perft 5 18103280 perft 6 454569900 id 174 -epd nrnk1rbb/p1p2ppp/3pq3/Qp2p3/1P1P4/8/P1P1PPPP/NRN1KRBB w fb - 2 9 +epd nrnk1rbb/p1p2ppp/3pq3/Qp2p3/1P1P4/8/P1P1PPPP/NRN1KRBB w fb - perft 1 28 perft 2 873 perft 3 25683 @@ -1577,7 +1577,7 @@ perft 5 23868737 perft 6 747991356 id 175 -epd bbnrnkrq/pp1ppp1p/6p1/2p5/6P1/P5RP/1PPPPP2/BBNRNK1Q w Dgd - 3 9 +epd bbnrnkrq/pp1ppp1p/6p1/2p5/6P1/P5RP/1PPPPP2/BBNRNK1Q w Dgd - perft 1 37 perft 2 1260 perft 3 45060 @@ -1586,7 +1586,7 @@ perft 5 54843403 perft 6 1898432768 id 176 -epd bnrb1rkq/ppnpppp1/3Q4/2p4p/7P/N7/PPPPPPP1/B1RBNKR1 w GC - 2 9 +epd bnrb1rkq/ppnpppp1/3Q4/2p4p/7P/N7/PPPPPPP1/B1RBNKR1 w GC - perft 1 38 perft 2 878 perft 3 31944 @@ -1595,7 +1595,7 @@ perft 5 28784300 perft 6 784569826 id 177 -epd bnrnkbrq/p1ppppp1/1p5p/8/P2PP3/5P2/1PP3PP/BNRNKBRQ w GCgc - 1 9 +epd bnrnkbrq/p1ppppp1/1p5p/8/P2PP3/5P2/1PP3PP/BNRNKBRQ w GCgc - perft 1 26 perft 2 617 perft 3 16992 @@ -1604,7 +1604,7 @@ perft 5 11965544 perft 6 311309576 id 178 -epd bnrnkrqb/pp2p2p/2pp1pp1/8/P7/2PP1P2/1P2P1PP/BNRNKRQB w FCfc - 0 9 +epd bnrnkrqb/pp2p2p/2pp1pp1/8/P7/2PP1P2/1P2P1PP/BNRNKRQB w FCfc - perft 1 26 perft 2 721 perft 3 19726 @@ -1613,7 +1613,7 @@ perft 5 15966934 perft 6 467132503 id 179 -epd nbbrnkr1/1pppp1p1/p6q/P4p1p/8/5P2/1PPPP1PP/NBBRNRKQ w gd - 2 9 +epd nbbrnkr1/1pppp1p1/p6q/P4p1p/8/5P2/1PPPP1PP/NBBRNRKQ w gd - perft 1 18 perft 2 556 perft 3 10484 @@ -1622,7 +1622,7 @@ perft 5 6629293 perft 6 202528241 id 180 -epd nrb1nkrq/2pp1ppp/p4b2/1p2p3/P4B2/3P4/1PP1PPPP/NR1BNRKQ w gb - 0 9 +epd nrb1nkrq/2pp1ppp/p4b2/1p2p3/P4B2/3P4/1PP1PPPP/NR1BNRKQ w gb - perft 1 24 perft 2 562 perft 3 14017 @@ -1631,7 +1631,7 @@ perft 5 9227883 perft 6 247634489 id 181 -epd nrbnkbrq/p3p1pp/1p6/2pp1P2/8/3PP3/PPP2P1P/NRBNKBRQ w GBgb - 0 9 +epd nrbnkbrq/p3p1pp/1p6/2pp1P2/8/3PP3/PPP2P1P/NRBNKBRQ w GBgb - perft 1 31 perft 2 746 perft 3 24819 @@ -1640,7 +1640,7 @@ perft 5 21019301 perft 6 542954168 id 182 -epd nrbnkrqb/pppp1p1p/4p1p1/8/7P/2P1P3/PPNP1PP1/1RBNKRQB w FBfb - 0 9 +epd nrbnkrqb/pppp1p1p/4p1p1/8/7P/2P1P3/PPNP1PP1/1RBNKRQB w FBfb - perft 1 20 perft 2 459 perft 3 9998 @@ -1649,7 +1649,7 @@ perft 5 5760165 perft 6 146614723 id 183 -epd nbrn1krq/ppp1p2p/6b1/3p1pp1/8/4N1PP/PPPPPP2/NBR1BRKQ w gc - 1 9 +epd nbrn1krq/ppp1p2p/6b1/3p1pp1/8/4N1PP/PPPPPP2/NBR1BRKQ w gc - perft 1 27 perft 2 835 perft 3 23632 @@ -1658,7 +1658,7 @@ perft 5 22667987 perft 6 760795567 id 184 -epd nrnbbkrq/p1pp2pp/5p2/1p6/2P1pP1B/1P6/P2PP1PP/NRNB1KRQ w GBgb - 0 9 +epd nrnbbkrq/p1pp2pp/5p2/1p6/2P1pP1B/1P6/P2PP1PP/NRNB1KRQ w GBgb - perft 1 24 perft 2 646 perft 3 16102 @@ -1667,7 +1667,7 @@ perft 5 11489727 perft 6 324948755 id 185 -epd nrn1bbrq/1ppkppp1/p2p3p/8/1P3N2/4P3/P1PP1PPP/NR1KBBRQ w GB - 2 9 +epd nrn1bbrq/1ppkppp1/p2p3p/8/1P3N2/4P3/P1PP1PPP/NR1KBBRQ w GB - perft 1 32 perft 2 591 perft 3 18722 @@ -1676,7 +1676,7 @@ perft 5 12069159 perft 6 269922838 id 186 -epd n1krbrqb/1ppppppp/p7/8/4n3/P4P1P/1PPPPQP1/NRNKBR1B w FB - 2 9 +epd n1krbrqb/1ppppppp/p7/8/4n3/P4P1P/1PPPPQP1/NRNKBR1B w FB - perft 1 26 perft 2 639 perft 3 16988 @@ -1685,7 +1685,7 @@ perft 5 12167153 perft 6 312633873 id 187 -epd n1rnkrbq/1p1ppp1p/8/p1p1b1p1/3PQ1P1/4N3/PPP1PP1P/NBR1KRB1 w FCfc - 0 9 +epd n1rnkrbq/1p1ppp1p/8/p1p1b1p1/3PQ1P1/4N3/PPP1PP1P/NBR1KRB1 w FCfc - perft 1 35 perft 2 1027 perft 3 35731 @@ -1694,7 +1694,7 @@ perft 5 35738410 perft 6 1060661628 id 188 -epd nrnbkrbq/2pp1pp1/pp6/4p2p/P7/5PPP/1PPPP3/NRNBKRBQ w FBfb - 0 9 +epd nrnbkrbq/2pp1pp1/pp6/4p2p/P7/5PPP/1PPPP3/NRNBKRBQ w FBfb - perft 1 26 perft 2 628 perft 3 16731 @@ -1703,7 +1703,7 @@ perft 5 11920087 perft 6 331498921 id 189 -epd 1rnkrbbq/pp1p2pp/1n3p2/1Bp1p3/1P6/1N2P3/P1PP1PPP/1RNKR1BQ w EBeb - 0 9 +epd 1rnkrbbq/pp1p2pp/1n3p2/1Bp1p3/1P6/1N2P3/P1PP1PPP/1RNKR1BQ w EBeb - perft 1 33 perft 2 992 perft 3 32244 @@ -1712,7 +1712,7 @@ perft 5 31703749 perft 6 980306735 id 190 -epd nr1krqbb/p1ppppp1/8/1p5p/1Pn5/5P2/P1PPP1PP/NRNKRQBB w EBeb - 0 9 +epd nr1krqbb/p1ppppp1/8/1p5p/1Pn5/5P2/P1PPP1PP/NRNKRQBB w EBeb - perft 1 24 perft 2 670 perft 3 15985 @@ -1721,7 +1721,7 @@ perft 5 11371067 perft 6 325556465 id 191 -epd bbq1rkr1/1ppppppp/p1n2n2/8/2P2P2/1P6/PQ1PP1PP/BB1NRKNR w HEe - 3 9 +epd bbq1rkr1/1ppppppp/p1n2n2/8/2P2P2/1P6/PQ1PP1PP/BB1NRKNR w HEe - perft 1 32 perft 2 794 perft 3 26846 @@ -1730,7 +1730,7 @@ perft 5 24085223 perft 6 645633370 id 192 -epd b1nbrknr/1qppp1pp/p4p2/1p6/6P1/P2NP3/1PPP1P1P/BQ1BRKNR w HEhe - 1 9 +epd b1nbrknr/1qppp1pp/p4p2/1p6/6P1/P2NP3/1PPP1P1P/BQ1BRKNR w HEhe - perft 1 25 perft 2 663 perft 3 17138 @@ -1739,7 +1739,7 @@ perft 5 13157826 perft 6 389603029 id 193 -epd bqnrk1nr/pp2ppbp/6p1/2pp4/2P5/5P2/PPQPP1PP/B1NRKBNR w HDhd - 0 9 +epd bqnrk1nr/pp2ppbp/6p1/2pp4/2P5/5P2/PPQPP1PP/B1NRKBNR w HDhd - perft 1 26 perft 2 850 perft 3 22876 @@ -1748,7 +1748,7 @@ perft 5 21341087 perft 6 719712622 id 194 -epd bqnrknrb/1ppp1p1p/p7/6p1/1P2p3/P1PN4/3PPPPP/BQ1RKNRB w GDgd - 0 9 +epd bqnrknrb/1ppp1p1p/p7/6p1/1P2p3/P1PN4/3PPPPP/BQ1RKNRB w GDgd - perft 1 25 perft 2 721 perft 3 19290 @@ -1757,7 +1757,7 @@ perft 5 16391601 perft 6 511725087 id 195 -epd q1b1rknr/pp1pppp1/4n2p/2p1b3/1PP5/4P3/PQ1P1PPP/1BBNRKNR w HEhe - 1 9 +epd q1b1rknr/pp1pppp1/4n2p/2p1b3/1PP5/4P3/PQ1P1PPP/1BBNRKNR w HEhe - perft 1 32 perft 2 975 perft 3 32566 @@ -1766,7 +1766,7 @@ perft 5 32649943 perft 6 962536105 id 196 -epd qnbbrknr/1p1ppppp/8/p1p5/5P2/PP1P4/2P1P1PP/QNBBRKNR w HEhe - 0 9 +epd qnbbrknr/1p1ppppp/8/p1p5/5P2/PP1P4/2P1P1PP/QNBBRKNR w HEhe - perft 1 27 perft 2 573 perft 3 16331 @@ -1775,7 +1775,7 @@ perft 5 11562434 perft 6 301166330 id 197 -epd q1brkb1r/p1pppppp/np3B2/8/6n1/1P5N/P1PPPPPP/QN1RKB1R w HDhd - 0 9 +epd q1brkb1r/p1pppppp/np3B2/8/6n1/1P5N/P1PPPPPP/QN1RKB1R w HDhd - perft 1 32 perft 2 984 perft 3 31549 @@ -1784,7 +1784,7 @@ perft 5 32597704 perft 6 1075429389 id 198 -epd qn1rk1rb/p1pppppp/1p2n3/8/2b5/4NPP1/PPPPP1RP/QNBRK2B w Dgd - 4 9 +epd qn1rk1rb/p1pppppp/1p2n3/8/2b5/4NPP1/PPPPP1RP/QNBRK2B w Dgd - perft 1 22 perft 2 802 perft 3 19156 @@ -1793,7 +1793,7 @@ perft 5 17761431 perft 6 650603534 id 199 -epd qbnrbknr/ppp2p1p/8/3pp1p1/1PP1B3/5N2/P2PPPPP/Q1NRBK1R w HDhd - 0 9 +epd qbnrbknr/ppp2p1p/8/3pp1p1/1PP1B3/5N2/P2PPPPP/Q1NRBK1R w HDhd - perft 1 34 perft 2 943 perft 3 32506 @@ -1802,7 +1802,7 @@ perft 5 32523099 perft 6 955802240 id 200 -epd qnrbb1nr/pp1p1ppp/2p2k2/4p3/4P3/5PPP/PPPP4/QNRBBKNR w HC - 0 9 +epd qnrbb1nr/pp1p1ppp/2p2k2/4p3/4P3/5PPP/PPPP4/QNRBBKNR w HC - perft 1 20 perft 2 460 perft 3 10287 @@ -1811,7 +1811,7 @@ perft 5 5846781 perft 6 140714047 id 201 -epd qnr1bbnr/ppk1p1pp/3p4/2p2p2/8/2P5/PP1PPPPP/QNKRBBNR w - - 1 9 +epd qnr1bbnr/ppk1p1pp/3p4/2p2p2/8/2P5/PP1PPPPP/QNKRBBNR w - - perft 1 19 perft 2 572 perft 3 11834 @@ -1820,7 +1820,7 @@ perft 5 7994547 perft 6 243724815 id 202 -epd qnrkbnrb/1p1p1ppp/2p5/4p3/p7/N1BP4/PPP1PPPP/Q1R1KNRB w gc - 0 9 +epd qnrkbnrb/1p1p1ppp/2p5/4p3/p7/N1BP4/PPP1PPPP/Q1R1KNRB w gc - perft 1 27 perft 2 579 perft 3 16233 @@ -1829,7 +1829,7 @@ perft 5 10845146 perft 6 268229097 id 203 -epd qbnrkn1r/1pppp1p1/p3bp2/2BN3p/8/5P2/PPPPP1PP/QBNRK2R w HDhd - 0 9 +epd qbnrkn1r/1pppp1p1/p3bp2/2BN3p/8/5P2/PPPPP1PP/QBNRK2R w HDhd - perft 1 40 perft 2 1027 perft 3 38728 @@ -1838,7 +1838,7 @@ perft 5 38511307 perft 6 1104094381 id 204 -epd qnrbknbr/1pp2ppp/4p3/p6N/2p5/8/PPPPPPPP/Q1RBK1BR w HChc - 0 9 +epd qnrbknbr/1pp2ppp/4p3/p6N/2p5/8/PPPPPPPP/Q1RBK1BR w HChc - perft 1 22 perft 2 510 perft 3 11844 @@ -1847,7 +1847,7 @@ perft 5 7403327 perft 6 200581103 id 205 -epd 1qkrnbbr/p1pppppp/2n5/1p6/8/5NP1/PPPPPP1P/QNRK1BBR w HC - 4 9 +epd 1qkrnbbr/p1pppppp/2n5/1p6/8/5NP1/PPPPPP1P/QNRK1BBR w HC - perft 1 24 perft 2 549 perft 3 13987 @@ -1856,7 +1856,7 @@ perft 5 9396521 perft 6 255676649 id 206 -epd q1rknr1b/1ppppppb/2n5/p2B3p/8/1PN3P1/P1PPPP1P/Q1RKNRB1 w FCfc - 3 9 +epd q1rknr1b/1ppppppb/2n5/p2B3p/8/1PN3P1/P1PPPP1P/Q1RKNRB1 w FCfc - perft 1 31 perft 2 924 perft 3 28520 @@ -1865,7 +1865,7 @@ perft 5 27463479 perft 6 847726572 id 207 -epd bbnqrk1r/pp1pppp1/2p4p/8/6n1/1N1P1P2/PPP1P1PP/BBQ1RKNR w HEhe - 4 9 +epd bbnqrk1r/pp1pppp1/2p4p/8/6n1/1N1P1P2/PPP1P1PP/BBQ1RKNR w HEhe - perft 1 24 perft 2 804 perft 3 20147 @@ -1874,7 +1874,7 @@ perft 5 18024195 perft 6 595947631 id 208 -epd bn1brknr/ppp1p1pp/5p2/3p4/6qQ/3P3P/PPP1PPP1/BN1BRKNR w HEhe - 4 9 +epd bn1brknr/ppp1p1pp/5p2/3p4/6qQ/3P3P/PPP1PPP1/BN1BRKNR w HEhe - perft 1 25 perft 2 854 perft 3 22991 @@ -1883,7 +1883,7 @@ perft 5 20290974 perft 6 600195008 id 209 -epd 1nqrkbnr/2pp1ppp/pp2p3/3b4/2P5/N7/PP1PPPPP/B1QRKBNR w HDhd - 0 9 +epd 1nqrkbnr/2pp1ppp/pp2p3/3b4/2P5/N7/PP1PPPPP/B1QRKBNR w HDhd - perft 1 22 perft 2 651 perft 3 16173 @@ -1892,7 +1892,7 @@ perft 5 13133439 perft 6 390886040 id 210 -epd bnqrk1rb/1pp1pppp/p2p4/4n3/2PPP3/8/PP3PPP/BNQRKNRB w GDgd - 1 9 +epd bnqrk1rb/1pp1pppp/p2p4/4n3/2PPP3/8/PP3PPP/BNQRKNRB w GDgd - perft 1 30 perft 2 950 perft 3 28169 @@ -1901,7 +1901,7 @@ perft 5 27610213 perft 6 880739164 id 211 -epd nbb1rknr/1ppq1ppp/3p4/p3p3/4P3/1N2R3/PPPP1PPP/1BBQ1KNR w Hhe - 2 9 +epd nbb1rknr/1ppq1ppp/3p4/p3p3/4P3/1N2R3/PPPP1PPP/1BBQ1KNR w Hhe - perft 1 33 perft 2 988 perft 3 31293 @@ -1910,7 +1910,7 @@ perft 5 30894863 perft 6 985384035 id 212 -epd nqbbrknr/2ppp2p/pp4p1/5p2/7P/3P1P2/PPPBP1P1/NQ1BRKNR w HEhe - 0 9 +epd nqbbrknr/2ppp2p/pp4p1/5p2/7P/3P1P2/PPPBP1P1/NQ1BRKNR w HEhe - perft 1 27 perft 2 492 perft 3 13266 @@ -1919,7 +1919,7 @@ perft 5 7583292 perft 6 175376176 id 213 -epd 1qbrkb1r/pppppppp/8/3n4/4P1n1/PN6/1PPP1P1P/1QBRKBNR w HDhd - 3 9 +epd 1qbrkb1r/pppppppp/8/3n4/4P1n1/PN6/1PPP1P1P/1QBRKBNR w HDhd - perft 1 28 perft 2 800 perft 3 21982 @@ -1928,7 +1928,7 @@ perft 5 17313279 perft 6 507140861 id 214 -epd 1qbrknrb/1p1ppppp/1np5/8/p4P1P/4P1N1/PPPP2P1/NQBRK1RB w GDgd - 0 9 +epd 1qbrknrb/1p1ppppp/1np5/8/p4P1P/4P1N1/PPPP2P1/NQBRK1RB w GDgd - perft 1 21 perft 2 482 perft 3 10581 @@ -1937,7 +1937,7 @@ perft 5 6218644 perft 6 168704845 id 215 -epd nbqrbkr1/ppp1pppp/8/3p4/6n1/2P2PPN/PP1PP2P/NBQRBK1R w HDd - 1 9 +epd nbqrbkr1/ppp1pppp/8/3p4/6n1/2P2PPN/PP1PP2P/NBQRBK1R w HDd - perft 1 29 perft 2 921 perft 3 25748 @@ -1946,7 +1946,7 @@ perft 5 24138518 perft 6 806554650 id 216 -epd nqrb1knr/1ppbpp1p/p7/3p2p1/2P3P1/5P1P/PP1PP3/NQRBBKNR w HChc - 1 9 +epd nqrb1knr/1ppbpp1p/p7/3p2p1/2P3P1/5P1P/PP1PP3/NQRBBKNR w HChc - perft 1 31 perft 2 803 perft 3 25857 @@ -1955,7 +1955,7 @@ perft 5 21998733 perft 6 583349773 id 217 -epd 1qrkbbr1/pppp1ppp/1n3n2/4p3/5P2/1N6/PPPPP1PP/1QRKBBNR w HCc - 0 9 +epd 1qrkbbr1/pppp1ppp/1n3n2/4p3/5P2/1N6/PPPPP1PP/1QRKBBNR w HCc - perft 1 25 perft 2 715 perft 3 19118 @@ -1964,7 +1964,7 @@ perft 5 15514933 perft 6 459533767 id 218 -epd nqrkb1rb/pp2pppp/2p1n3/3p4/3PP1N1/8/PPP2PPP/NQRKB1RB w GCgc - 0 9 +epd nqrkb1rb/pp2pppp/2p1n3/3p4/3PP1N1/8/PPP2PPP/NQRKB1RB w GCgc - perft 1 26 perft 2 795 perft 3 21752 @@ -1973,7 +1973,7 @@ perft 5 19185851 perft 6 616508881 id 219 -epd nb1rknbr/pp2ppp1/8/2Bp3p/6P1/2P2P1q/PP1PP2P/NBQRKN1R w HDhd - 0 9 +epd nb1rknbr/pp2ppp1/8/2Bp3p/6P1/2P2P1q/PP1PP2P/NBQRKN1R w HDhd - perft 1 35 perft 2 1391 perft 3 43025 @@ -1982,7 +1982,7 @@ perft 5 53033675 perft 6 2139267832 id 220 -epd nqrbkn1r/pp1pp1pp/8/2p2p2/5P2/P3B2P/1PbPP1P1/NQRBKN1R w HChc - 0 9 +epd nqrbkn1r/pp1pp1pp/8/2p2p2/5P2/P3B2P/1PbPP1P1/NQRBKN1R w HChc - perft 1 23 perft 2 758 perft 3 19439 @@ -1991,7 +1991,7 @@ perft 5 18296195 perft 6 628403401 id 221 -epd nqrknbbr/pp1pppp1/7p/2p5/7P/1P1N4/P1PPPPPB/NQRK1B1R w HChc - 2 9 +epd nqrknbbr/pp1pppp1/7p/2p5/7P/1P1N4/P1PPPPPB/NQRK1B1R w HChc - perft 1 29 perft 2 824 perft 3 23137 @@ -2000,7 +2000,7 @@ perft 5 19429491 perft 6 595493802 id 222 -epd 1qrknrbb/B1p1pppp/8/1p1p4/2n2P2/1P6/P1PPP1PP/NQRKNR1B w FCfc - 0 9 +epd 1qrknrbb/B1p1pppp/8/1p1p4/2n2P2/1P6/P1PPP1PP/NQRKNR1B w FCfc - perft 1 28 perft 2 771 perft 3 20237 @@ -2009,7 +2009,7 @@ perft 5 16065378 perft 6 483037840 id 223 -epd bbnrqk1r/1ppppppp/8/7n/1p6/P6P/1BPPPPP1/1BNRQKNR w HDhd - 0 9 +epd bbnrqk1r/1ppppppp/8/7n/1p6/P6P/1BPPPPP1/1BNRQKNR w HDhd - perft 1 25 perft 2 601 perft 3 15471 @@ -2018,7 +2018,7 @@ perft 5 10697065 perft 6 289472497 id 224 -epd bnrbqknr/ppp3p1/3ppp1Q/7p/3P4/1P6/P1P1PPPP/BNRB1KNR w HChc - 0 9 +epd bnrbqknr/ppp3p1/3ppp1Q/7p/3P4/1P6/P1P1PPPP/BNRB1KNR w HChc - perft 1 32 perft 2 845 perft 3 26876 @@ -2027,7 +2027,7 @@ perft 5 23717883 perft 6 682154649 id 225 -epd bn1qkb1r/pprppppp/8/2p5/2PPP1n1/8/PPR2PPP/BN1QKBNR w Hh - 1 9 +epd bn1qkb1r/pprppppp/8/2p5/2PPP1n1/8/PPR2PPP/BN1QKBNR w Hh - perft 1 32 perft 2 856 perft 3 27829 @@ -2036,7 +2036,7 @@ perft 5 25245957 perft 6 727424329 id 226 -epd 1nrqknrb/p1pp1ppp/1p2p3/3N4/5P1P/5b2/PPPPP3/B1RQKNRB w GCgc - 2 9 +epd 1nrqknrb/p1pp1ppp/1p2p3/3N4/5P1P/5b2/PPPPP3/B1RQKNRB w GCgc - perft 1 33 perft 2 873 perft 3 27685 @@ -2045,7 +2045,7 @@ perft 5 25128076 perft 6 745401024 id 227 -epd nbbrqrk1/pppppppp/8/2N1n3/P7/6P1/1PPPPP1P/1BBRQKNR w HD - 3 9 +epd nbbrqrk1/pppppppp/8/2N1n3/P7/6P1/1PPPPP1P/1BBRQKNR w HD - perft 1 25 perft 2 555 perft 3 14339 @@ -2054,7 +2054,7 @@ perft 5 9153089 perft 6 234841945 id 228 -epd 1rbbqknr/1ppp1pp1/1n2p3/p6p/4P1P1/P6N/1PPP1P1P/NRBBQK1R w HBhb - 0 9 +epd 1rbbqknr/1ppp1pp1/1n2p3/p6p/4P1P1/P6N/1PPP1P1P/NRBBQK1R w HBhb - perft 1 25 perft 2 693 perft 3 18652 @@ -2063,7 +2063,7 @@ perft 5 15133381 perft 6 439344945 id 229 -epd nrq1kbnr/p1pbpppp/3p4/1p6/6P1/1N3N2/PPPPPP1P/1RBQKB1R w HBhb - 4 9 +epd nrq1kbnr/p1pbpppp/3p4/1p6/6P1/1N3N2/PPPPPP1P/1RBQKB1R w HBhb - perft 1 24 perft 2 648 perft 3 16640 @@ -2072,7 +2072,7 @@ perft 5 12871967 perft 6 380436777 id 230 -epd nr1qknr1/p1pppp1p/b5p1/1p6/8/P4PP1/1bPPP1RP/NRBQKN1B w Bgb - 0 9 +epd nr1qknr1/p1pppp1p/b5p1/1p6/8/P4PP1/1bPPP1RP/NRBQKN1B w Bgb - perft 1 18 perft 2 533 perft 3 11215 @@ -2081,7 +2081,7 @@ perft 5 7777833 perft 6 234905172 id 231 -epd nbrqbknr/1ppp2pp/8/4pp2/p2PP1P1/7N/PPP2P1P/NBRQBK1R w HChc - 0 9 +epd nbrqbknr/1ppp2pp/8/4pp2/p2PP1P1/7N/PPP2P1P/NBRQBK1R w HChc - perft 1 29 perft 2 803 perft 3 24416 @@ -2090,7 +2090,7 @@ perft 5 22305910 perft 6 672322762 id 232 -epd nr1b1k1r/ppp1pppp/2bp1n2/6P1/2P3q1/5P2/PP1PP2P/NRQBBKNR w HBhb - 1 9 +epd nr1b1k1r/ppp1pppp/2bp1n2/6P1/2P3q1/5P2/PP1PP2P/NRQBBKNR w HBhb - perft 1 27 perft 2 1199 perft 3 30908 @@ -2099,7 +2099,7 @@ perft 5 35121759 perft 6 1418677099 id 233 -epd nrqkbbnr/2pppp1p/p7/1p6/2P1Pp2/8/PPNP2PP/1RQKBBNR w HBhb - 0 9 +epd nrqkbbnr/2pppp1p/p7/1p6/2P1Pp2/8/PPNP2PP/1RQKBBNR w HBhb - perft 1 28 perft 2 613 perft 3 17874 @@ -2108,7 +2108,7 @@ perft 5 13097064 perft 6 345294379 id 234 -epd 1rqkbnrb/pp1ppp1p/1n4p1/B1p5/3PP3/4N3/PPP2PPP/NRQK2RB w GBgb - 0 9 +epd 1rqkbnrb/pp1ppp1p/1n4p1/B1p5/3PP3/4N3/PPP2PPP/NRQK2RB w GBgb - perft 1 33 perft 2 723 perft 3 23991 @@ -2117,7 +2117,7 @@ perft 5 19715083 perft 6 535650233 id 235 -epd nbrqkn1r/1pppp2p/5pp1/p2b4/5P2/P2PN3/1PP1P1PP/NBRQK1BR w HChc - 2 9 +epd nbrqkn1r/1pppp2p/5pp1/p2b4/5P2/P2PN3/1PP1P1PP/NBRQK1BR w HChc - perft 1 23 perft 2 607 perft 3 15482 @@ -2126,7 +2126,7 @@ perft 5 11026383 perft 6 290708878 id 236 -epd nrqbknbr/pp1pppp1/8/2p4p/P3PP2/8/1PPP2PP/NRQBKNBR w HBhb - 1 9 +epd nrqbknbr/pp1pppp1/8/2p4p/P3PP2/8/1PPP2PP/NRQBKNBR w HBhb - perft 1 26 perft 2 700 perft 3 19371 @@ -2135,7 +2135,7 @@ perft 5 16058815 perft 6 485460242 id 237 -epd nrqknbbr/p2pppp1/1pp5/6Qp/3P4/1P3P2/P1P1P1PP/NR1KNBBR w HBhb - 0 9 +epd nrqknbbr/p2pppp1/1pp5/6Qp/3P4/1P3P2/P1P1P1PP/NR1KNBBR w HBhb - perft 1 40 perft 2 905 perft 3 32932 @@ -2144,7 +2144,7 @@ perft 5 29263502 perft 6 791963709 id 238 -epd nrqknrbb/1p3ppp/p2p4/2p1p3/1P6/3PP1P1/P1P2P1P/NRQKNRBB w FBfb - 0 9 +epd nrqknrbb/1p3ppp/p2p4/2p1p3/1P6/3PP1P1/P1P2P1P/NRQKNRBB w FBfb - perft 1 29 perft 2 780 perft 3 22643 @@ -2153,7 +2153,7 @@ perft 5 19532077 perft 6 593181101 id 239 -epd 1bnrkqnr/p1pppp2/7p/1p4p1/4b3/7N/PPPP1PPP/BBNRKQ1R w HDhd - 0 9 +epd 1bnrkqnr/p1pppp2/7p/1p4p1/4b3/7N/PPPP1PPP/BBNRKQ1R w HDhd - perft 1 25 perft 2 725 perft 3 19808 @@ -2162,7 +2162,7 @@ perft 5 16661676 perft 6 487354613 id 240 -epd bnrbkq1r/pp2p1pp/5n2/2pp1p2/P7/N1PP4/1P2PPPP/B1RBKQNR w HChc - 1 9 +epd bnrbkq1r/pp2p1pp/5n2/2pp1p2/P7/N1PP4/1P2PPPP/B1RBKQNR w HChc - perft 1 24 perft 2 745 perft 3 18494 @@ -2171,7 +2171,7 @@ perft 5 15079602 perft 6 488924040 id 241 -epd 2rkqbnr/p1pppppp/2b5/1pn5/1P3P1Q/2B5/P1PPP1PP/1NRK1BNR w HChc - 3 9 +epd 2rkqbnr/p1pppppp/2b5/1pn5/1P3P1Q/2B5/P1PPP1PP/1NRK1BNR w HChc - perft 1 33 perft 2 904 perft 3 30111 @@ -2180,7 +2180,7 @@ perft 5 28194726 perft 6 801757709 id 242 -epd bnrkqnrb/2pppp2/8/pp4pp/1P5P/6P1/P1PPPPB1/BNRKQNR1 w GCgc - 0 9 +epd bnrkqnrb/2pppp2/8/pp4pp/1P5P/6P1/P1PPPPB1/BNRKQNR1 w GCgc - perft 1 34 perft 2 1059 perft 3 34090 @@ -2189,7 +2189,7 @@ perft 5 33195397 perft 6 1036498304 id 243 -epd 1bbrkq1r/pppp2pp/1n2pp1n/8/2PP4/1N4P1/PP2PP1P/1BBRKQNR w HDhd - 1 9 +epd 1bbrkq1r/pppp2pp/1n2pp1n/8/2PP4/1N4P1/PP2PP1P/1BBRKQNR w HDhd - perft 1 33 perft 2 891 perft 3 28907 @@ -2198,7 +2198,7 @@ perft 5 26970098 perft 6 788040469 id 244 -epd nrbbkqnr/1p2pp1p/p1p3p1/3p4/8/1PP5/P2PPPPP/NRBBKQNR w HBhb - 0 9 +epd nrbbkqnr/1p2pp1p/p1p3p1/3p4/8/1PP5/P2PPPPP/NRBBKQNR w HBhb - perft 1 21 perft 2 567 perft 3 13212 @@ -2207,7 +2207,7 @@ perft 5 9539687 perft 6 284426039 id 245 -epd 1rbkqbr1/ppp1pppp/1n5n/3p4/3P4/1PP3P1/P3PP1P/NRBKQBNR w HBb - 1 9 +epd 1rbkqbr1/ppp1pppp/1n5n/3p4/3P4/1PP3P1/P3PP1P/NRBKQBNR w HBb - perft 1 27 perft 2 752 perft 3 20686 @@ -2216,7 +2216,7 @@ perft 5 16986290 perft 6 521817800 id 246 -epd nrbkq1rb/1ppp1pp1/4p1n1/p6p/2PP4/5P2/PPK1P1PP/NRB1QNRB w gb - 0 9 +epd nrbkq1rb/1ppp1pp1/4p1n1/p6p/2PP4/5P2/PPK1P1PP/NRB1QNRB w gb - perft 1 35 perft 2 697 perft 3 23678 @@ -2225,7 +2225,7 @@ perft 5 16906409 perft 6 390324794 id 247 -epd nbrkbqnr/p2pp1p1/5p2/1pp4p/7P/3P2P1/PPP1PP2/NBKRBQNR w hc - 0 9 +epd nbrkbqnr/p2pp1p1/5p2/1pp4p/7P/3P2P1/PPP1PP2/NBKRBQNR w hc - perft 1 25 perft 2 679 perft 3 17223 @@ -2234,7 +2234,7 @@ perft 5 12879258 perft 6 376652259 id 248 -epd nrkb1qnr/ppppp1p1/6bp/5p2/1PP1P1P1/8/P2P1P1P/NRKBBQNR w HBhb - 1 9 +epd nrkb1qnr/ppppp1p1/6bp/5p2/1PP1P1P1/8/P2P1P1P/NRKBBQNR w HBhb - perft 1 32 perft 2 761 perft 3 24586 @@ -2243,7 +2243,7 @@ perft 5 20671433 perft 6 568524724 id 249 -epd nrk1bbnr/p1q1pppp/1ppp4/8/3P3P/4K3/PPP1PPP1/NR1QBBNR w hb - 0 9 +epd nrk1bbnr/p1q1pppp/1ppp4/8/3P3P/4K3/PPP1PPP1/NR1QBBNR w hb - perft 1 30 perft 2 719 perft 3 21683 @@ -2252,7 +2252,7 @@ perft 5 16278120 perft 6 423649784 id 250 -epd nrkqbr1b/1pppp1pp/5pn1/p6N/1P3P2/8/P1PPP1PP/NRKQB1RB w GBb - 0 9 +epd nrkqbr1b/1pppp1pp/5pn1/p6N/1P3P2/8/P1PPP1PP/NRKQB1RB w GBb - perft 1 26 perft 2 494 perft 3 13815 @@ -2261,7 +2261,7 @@ perft 5 8763742 perft 6 206993496 id 251 -epd nbrkq2r/pppp1bpp/4p1n1/5p2/7P/2P3N1/PP1PPPP1/NBKRQ1BR w hc - 0 9 +epd nbrkq2r/pppp1bpp/4p1n1/5p2/7P/2P3N1/PP1PPPP1/NBKRQ1BR w hc - perft 1 27 perft 2 701 perft 3 19536 @@ -2270,7 +2270,7 @@ perft 5 15394667 perft 6 443506342 id 252 -epd nrkbqnbr/2ppp2p/pp6/5pp1/P1P5/8/1P1PPPPP/NRKBQNBR w HBhb - 0 9 +epd nrkbqnbr/2ppp2p/pp6/5pp1/P1P5/8/1P1PPPPP/NRKBQNBR w HBhb - perft 1 21 perft 2 487 perft 3 11341 @@ -2279,7 +2279,7 @@ perft 5 7218486 perft 6 193586674 id 253 -epd nr1qnbbr/pk1pppp1/1pp4p/8/3P4/5P1P/PPP1P1P1/NRKQNBBR w HB - 0 9 +epd nr1qnbbr/pk1pppp1/1pp4p/8/3P4/5P1P/PPP1P1P1/NRKQNBBR w HB - perft 1 22 perft 2 546 perft 3 13615 @@ -2288,7 +2288,7 @@ perft 5 9587439 perft 6 259830255 id 254 -epd nrkq1rbb/pp1ppp1p/2pn4/8/PP3Pp1/7P/2PPP1P1/NRKQNRBB w FBfb - 0 9 +epd nrkq1rbb/pp1ppp1p/2pn4/8/PP3Pp1/7P/2PPP1P1/NRKQNRBB w FBfb - perft 1 26 perft 2 839 perft 3 22075 @@ -2297,7 +2297,7 @@ perft 5 19867117 perft 6 658535326 id 255 -epd b2rknqr/pp1ppppp/8/2P5/n7/P7/1PPNPPPb/BBNRK1QR w HDhd - 2 9 +epd b2rknqr/pp1ppppp/8/2P5/n7/P7/1PPNPPPb/BBNRK1QR w HDhd - perft 1 24 perft 2 699 perft 3 19523 @@ -2306,7 +2306,7 @@ perft 5 17734818 perft 6 535094237 id 256 -epd bnrbknqr/pp2p2p/2p3p1/3p1p2/8/3P4/PPPNPPPP/B1RBKNQR w HChc - 0 9 +epd bnrbknqr/pp2p2p/2p3p1/3p1p2/8/3P4/PPPNPPPP/B1RBKNQR w HChc - perft 1 23 perft 2 580 perft 3 14320 @@ -2315,7 +2315,7 @@ perft 5 10133092 perft 6 288041554 id 257 -epd bnrknb1r/pppp2pp/8/4pp2/6P1/3P3P/qPP1PPQ1/BNRKNB1R w HChc - 0 9 +epd bnrknb1r/pppp2pp/8/4pp2/6P1/3P3P/qPP1PPQ1/BNRKNB1R w HChc - perft 1 28 perft 2 1100 perft 3 31813 @@ -2324,7 +2324,7 @@ perft 5 36142423 perft 6 1361341249 id 258 -epd b1rknqrb/ppp1p1p1/2np1p1p/8/4N3/6PQ/PPPPPP1P/B1RKN1RB w GCgc - 0 9 +epd b1rknqrb/ppp1p1p1/2np1p1p/8/4N3/6PQ/PPPPPP1P/B1RKN1RB w GCgc - perft 1 36 perft 2 629 perft 3 23082 @@ -2333,7 +2333,7 @@ perft 5 16897544 perft 6 367503974 id 259 -epd nb1rknqr/pbppp2p/6p1/1p3p2/5P2/3KP3/PPPP2PP/NBBR1NQR w hd - 2 9 +epd nb1rknqr/pbppp2p/6p1/1p3p2/5P2/3KP3/PPPP2PP/NBBR1NQR w hd - perft 1 18 perft 2 557 perft 3 9779 @@ -2342,7 +2342,7 @@ perft 5 5822387 perft 6 180936551 id 260 -epd nr1bknqr/1ppb1ppp/p7/3pp3/B7/2P3NP/PP1PPPP1/NRB1K1QR w HBhb - 2 9 +epd nr1bknqr/1ppb1ppp/p7/3pp3/B7/2P3NP/PP1PPPP1/NRB1K1QR w HBhb - perft 1 28 perft 2 688 perft 3 19541 @@ -2351,7 +2351,7 @@ perft 5 15153092 perft 6 425149249 id 261 -epd nrbkn2r/pppp1pqp/4p1p1/8/3P2P1/P3B3/P1P1PP1P/NR1KNBQR w HBhb - 1 9 +epd nrbkn2r/pppp1pqp/4p1p1/8/3P2P1/P3B3/P1P1PP1P/NR1KNBQR w HBhb - perft 1 32 perft 2 808 perft 3 25578 @@ -2360,7 +2360,7 @@ perft 5 22094260 perft 6 609377239 id 262 -epd nrbknqrb/2p1ppp1/1p6/p2p2Bp/1P6/3P1P2/P1P1P1PP/NR1KNQRB w GBgb - 0 9 +epd nrbknqrb/2p1ppp1/1p6/p2p2Bp/1P6/3P1P2/P1P1P1PP/NR1KNQRB w GBgb - perft 1 30 perft 2 625 perft 3 18288 @@ -2369,7 +2369,7 @@ perft 5 12225742 perft 6 301834282 id 263 -epd nbr1knqr/1pp1p1pp/3p1pb1/8/7P/5P2/PPPPPQP1/NBRKBN1R w HC - 2 9 +epd nbr1knqr/1pp1p1pp/3p1pb1/8/7P/5P2/PPPPPQP1/NBRKBN1R w HC - perft 1 29 perft 2 863 perft 3 25767 @@ -2378,7 +2378,7 @@ perft 5 24965592 perft 6 799182442 id 264 -epd n1kbbnqr/prp2ppp/1p1p4/4p3/1P2P3/3P1B2/P1P2PPP/NRK1BNQR w HBh - 2 9 +epd n1kbbnqr/prp2ppp/1p1p4/4p3/1P2P3/3P1B2/P1P2PPP/NRK1BNQR w HBh - perft 1 26 perft 2 653 perft 3 17020 @@ -2387,7 +2387,7 @@ perft 5 12187583 perft 6 336872952 id 265 -epd nrknbbqr/pp3p1p/B3p1p1/2pp4/4P3/2N3P1/PPPP1P1P/NRK1B1QR w HBhb - 0 9 +epd nrknbbqr/pp3p1p/B3p1p1/2pp4/4P3/2N3P1/PPPP1P1P/NRK1B1QR w HBhb - perft 1 29 perft 2 683 perft 3 19755 @@ -2396,7 +2396,7 @@ perft 5 14684565 perft 6 394951291 id 266 -epd n1knbqrb/pr1p1ppp/Qp6/2p1p3/4P3/6P1/PPPP1P1P/NRKNB1RB w GBg - 2 9 +epd n1knbqrb/pr1p1ppp/Qp6/2p1p3/4P3/6P1/PPPP1P1P/NRKNB1RB w GBg - perft 1 31 perft 2 552 perft 3 17197 @@ -2405,7 +2405,7 @@ perft 5 11663330 perft 6 283583340 id 267 -epd nbrknqbr/p3p1pp/1p1p1p2/2p5/2Q1PP2/8/PPPP2PP/NBRKN1BR w HChc - 0 9 +epd nbrknqbr/p3p1pp/1p1p1p2/2p5/2Q1PP2/8/PPPP2PP/NBRKN1BR w HChc - perft 1 37 perft 2 913 perft 3 32470 @@ -2414,7 +2414,7 @@ perft 5 28899548 perft 6 759875563 id 268 -epd nrkb1qbr/pp1pppp1/5n2/7p/2p5/1N1NPP2/PPPP2PP/1RKB1QBR w HBhb - 0 9 +epd nrkb1qbr/pp1pppp1/5n2/7p/2p5/1N1NPP2/PPPP2PP/1RKB1QBR w HBhb - perft 1 25 perft 2 712 perft 3 18813 @@ -2423,7 +2423,7 @@ perft 5 15045589 perft 6 445074372 id 269 -epd nrk2bbr/pppqpppp/3p4/8/1P3nP1/3P4/P1P1PP1P/NRKNQBBR w HBhb - 1 9 +epd nrk2bbr/pppqpppp/3p4/8/1P3nP1/3P4/P1P1PP1P/NRKNQBBR w HBhb - perft 1 24 perft 2 814 perft 3 19954 @@ -2432,7 +2432,7 @@ perft 5 17603960 perft 6 592121050 id 270 -epd nrknqrbb/1p2ppp1/2pp4/Q6p/P2P3P/8/1PP1PPP1/NRKN1RBB w FBfb - 0 9 +epd nrknqrbb/1p2ppp1/2pp4/Q6p/P2P3P/8/1PP1PPP1/NRKN1RBB w FBfb - perft 1 34 perft 2 513 perft 3 16111 @@ -2441,7 +2441,7 @@ perft 5 9569590 perft 6 206509331 id 271 -epd bbnrk1rq/pp2p1pp/2ppn3/5p2/8/3NNP1P/PPPPP1P1/BB1RK1RQ w GDgd - 1 9 +epd bbnrk1rq/pp2p1pp/2ppn3/5p2/8/3NNP1P/PPPPP1P1/BB1RK1RQ w GDgd - perft 1 28 perft 2 697 perft 3 20141 @@ -2450,7 +2450,7 @@ perft 5 15301879 perft 6 410843713 id 272 -epd bnrbknrq/ppppp2p/6p1/5p2/4QPP1/8/PPPPP2P/BNRBKNR1 w GCgc - 0 9 +epd bnrbknrq/ppppp2p/6p1/5p2/4QPP1/8/PPPPP2P/BNRBKNR1 w GCgc - perft 1 37 perft 2 901 perft 3 32612 @@ -2459,7 +2459,7 @@ perft 5 31385912 perft 6 903831981 id 273 -epd bnkrnbrq/ppppp1p1/B6p/5p2/8/4P3/PPPP1PPP/BNKRN1RQ w - - 0 9 +epd bnkrnbrq/ppppp1p1/B6p/5p2/8/4P3/PPPP1PPP/BNKRN1RQ w - - perft 1 26 perft 2 417 perft 3 11124 @@ -2468,7 +2468,7 @@ perft 5 5980981 perft 6 133080499 id 274 -epd bnrk1rqb/2pppp1p/3n4/pp4p1/3Q1P2/2N3P1/PPPPP2P/B1RKNR1B w FCfc - 0 9 +epd bnrk1rqb/2pppp1p/3n4/pp4p1/3Q1P2/2N3P1/PPPPP2P/B1RKNR1B w FCfc - perft 1 49 perft 2 1655 perft 3 74590 @@ -2477,7 +2477,7 @@ perft 5 107234294 perft 6 3651608327 id 275 -epd nbbrk1rq/pp2pppp/2pp4/8/2P2n2/6N1/PP1PP1PP/NBBRKR1Q w Dgd - 0 9 +epd nbbrk1rq/pp2pppp/2pp4/8/2P2n2/6N1/PP1PP1PP/NBBRKR1Q w Dgd - perft 1 28 perft 2 960 perft 3 26841 @@ -2486,7 +2486,7 @@ perft 5 26083252 perft 6 846682836 id 276 -epd nrbb2rq/pppk1ppp/4p1n1/3p4/6P1/1BP5/PP1PPPQP/NRB1KNR1 w GB - 0 9 +epd nrbb2rq/pppk1ppp/4p1n1/3p4/6P1/1BP5/PP1PPPQP/NRB1KNR1 w GB - perft 1 28 perft 2 735 perft 3 22048 @@ -2495,7 +2495,7 @@ perft 5 18588316 perft 6 512048946 id 277 -epd nrbk1brq/p1ppppp1/7p/1p6/4P1nP/P7/1PPP1PP1/NRBKNBRQ w GBgb - 0 9 +epd nrbk1brq/p1ppppp1/7p/1p6/4P1nP/P7/1PPP1PP1/NRBKNBRQ w GBgb - perft 1 22 perft 2 572 perft 3 12739 @@ -2504,7 +2504,7 @@ perft 5 8525056 perft 6 247615348 id 278 -epd nrbk1rqb/1pp2ppp/5n2/p2pp3/5B2/1N1P2P1/PPP1PP1P/1R1KNRQB w FBfb - 0 9 +epd nrbk1rqb/1pp2ppp/5n2/p2pp3/5B2/1N1P2P1/PPP1PP1P/1R1KNRQB w FBfb - perft 1 35 perft 2 927 perft 3 31559 @@ -2513,7 +2513,7 @@ perft 5 28465693 perft 6 783048748 id 279 -epd nbrkb1rq/p1pp1ppp/4n3/4p3/Pp6/6N1/1PPPPPPP/NBRKBRQ1 w Cgc - 0 9 +epd nbrkb1rq/p1pp1ppp/4n3/4p3/Pp6/6N1/1PPPPPPP/NBRKBRQ1 w Cgc - perft 1 20 perft 2 456 perft 3 10271 @@ -2522,7 +2522,7 @@ perft 5 6124625 perft 6 154766108 id 280 -epd nrkb1nrq/p2pp1pp/1pp2p2/7b/6PP/5P2/PPPPP2N/NRKBB1RQ w GBgb - 0 9 +epd nrkb1nrq/p2pp1pp/1pp2p2/7b/6PP/5P2/PPPPP2N/NRKBB1RQ w GBgb - perft 1 21 perft 2 479 perft 3 11152 @@ -2531,7 +2531,7 @@ perft 5 6696458 perft 6 165253524 id 281 -epd nr1nbbr1/pppkpp1p/6p1/3p4/P6P/1P6/1RPPPPP1/N1KNBBRQ w G - 1 9 +epd nr1nbbr1/pppkpp1p/6p1/3p4/P6P/1P6/1RPPPPP1/N1KNBBRQ w G - perft 1 20 perft 2 498 perft 3 11304 @@ -2540,7 +2540,7 @@ perft 5 7197322 perft 6 188021682 id 282 -epd nrknbrqb/3p1ppp/ppN1p3/8/6P1/8/PPPPPP1P/1RKNBRQB w FBfb - 0 9 +epd nrknbrqb/3p1ppp/ppN1p3/8/6P1/8/PPPPPP1P/1RKNBRQB w FBfb - perft 1 32 perft 2 526 perft 3 17267 @@ -2549,7 +2549,7 @@ perft 5 10755190 perft 6 220058991 id 283 -epd nbrkn1bq/p1pppr1p/1p6/5pp1/8/1N2PP2/PPPP2PP/1BKRNRBQ w c - 1 9 +epd nbrkn1bq/p1pppr1p/1p6/5pp1/8/1N2PP2/PPPP2PP/1BKRNRBQ w c - perft 1 19 perft 2 491 perft 3 10090 @@ -2558,7 +2558,7 @@ perft 5 6230616 perft 6 180748649 id 284 -epd nrkbnrbq/ppppppp1/8/8/7p/PP3P2/2PPPRPP/NRKBN1BQ w Bfb - 0 9 +epd nrkbnrbq/ppppppp1/8/8/7p/PP3P2/2PPPRPP/NRKBN1BQ w Bfb - perft 1 16 perft 2 353 perft 3 6189 @@ -2567,7 +2567,7 @@ perft 5 3008668 perft 6 82706705 id 285 -epd nrknrbbq/p4ppp/2p1p3/1p1p4/1P2P3/2P5/P1NP1PPP/1RKNRBBQ w EBeb - 0 9 +epd nrknrbbq/p4ppp/2p1p3/1p1p4/1P2P3/2P5/P1NP1PPP/1RKNRBBQ w EBeb - perft 1 29 perft 2 728 perft 3 21915 @@ -2576,7 +2576,7 @@ perft 5 18231199 perft 6 511686397 id 286 -epd nrknr1bb/pppp1p2/7p/2qPp1p1/8/1P5P/P1P1PPP1/NRKNRQBB w EBeb - 0 9 +epd nrknr1bb/pppp1p2/7p/2qPp1p1/8/1P5P/P1P1PPP1/NRKNRQBB w EBeb - perft 1 20 perft 2 714 perft 3 14336 @@ -2585,7 +2585,7 @@ perft 5 11132758 perft 6 386064577 id 287 -epd bbqnrrkn/ppp2p1p/3pp1p1/8/1PP5/2Q5/P1BPPPPP/B2NRKRN w GE - 0 9 +epd bbqnrrkn/ppp2p1p/3pp1p1/8/1PP5/2Q5/P1BPPPPP/B2NRKRN w GE - perft 1 39 perft 2 593 perft 3 23446 @@ -2594,7 +2594,7 @@ perft 5 16764576 perft 6 346185058 id 288 -epd bqn1rkrn/p1p2ppp/1p1p4/4p3/3PP2b/8/PPP2PPP/BQNBRKRN w GEge - 2 9 +epd bqn1rkrn/p1p2ppp/1p1p4/4p3/3PP2b/8/PPP2PPP/BQNBRKRN w GEge - perft 1 25 perft 2 773 perft 3 20042 @@ -2603,7 +2603,7 @@ perft 5 16632403 perft 6 515838333 id 289 -epd bqnrkb1n/p1p1pprp/3p4/1p2P1p1/2PP4/8/PP3PPP/BQNRKBRN w GDd - 1 9 +epd bqnrkb1n/p1p1pprp/3p4/1p2P1p1/2PP4/8/PP3PPP/BQNRKBRN w GDd - perft 1 31 perft 2 860 perft 3 28102 @@ -2612,7 +2612,7 @@ perft 5 27233018 perft 6 813751250 id 290 -epd bqr1krnb/ppppppp1/7p/3n4/1P4P1/P4N2/2PPPP1P/BQNRKR1B w FDf - 3 9 +epd bqr1krnb/ppppppp1/7p/3n4/1P4P1/P4N2/2PPPP1P/BQNRKR1B w FDf - perft 1 31 perft 2 709 perft 3 22936 @@ -2621,7 +2621,7 @@ perft 5 18608857 perft 6 480498340 id 291 -epd qbbn1krn/pp3ppp/4r3/2ppp3/P1P4P/8/1P1PPPP1/QBBNRKRN w GEg - 1 9 +epd qbbn1krn/pp3ppp/4r3/2ppp3/P1P4P/8/1P1PPPP1/QBBNRKRN w GEg - perft 1 26 perft 2 775 perft 3 21100 @@ -2630,7 +2630,7 @@ perft 5 18476807 perft 6 582542257 id 292 -epd qnbbrkrn/1p1pp2p/p7/2p2pp1/8/4P2P/PPPP1PPK/QNBBRR1N w ge - 0 9 +epd qnbbrkrn/1p1pp2p/p7/2p2pp1/8/4P2P/PPPP1PPK/QNBBRR1N w ge - perft 1 25 perft 2 599 perft 3 15139 @@ -2639,7 +2639,7 @@ perft 5 10260500 perft 6 279222412 id 293 -epd qnbrkbrn/1ppp2p1/p3p2p/5p2/P4P2/1P6/2PPP1PP/QNBRKBRN w GDgd - 0 9 +epd qnbrkbrn/1ppp2p1/p3p2p/5p2/P4P2/1P6/2PPP1PP/QNBRKBRN w GDgd - perft 1 27 perft 2 588 perft 3 16735 @@ -2648,7 +2648,7 @@ perft 5 11640416 perft 6 293541380 id 294 -epd 1nbrkrnb/p1pppp1p/1pq3p1/8/4P3/P1P4N/1P1P1PPP/QNBRKR1B w FDfd - 1 9 +epd 1nbrkrnb/p1pppp1p/1pq3p1/8/4P3/P1P4N/1P1P1PPP/QNBRKR1B w FDfd - perft 1 18 perft 2 609 perft 3 11789 @@ -2657,7 +2657,7 @@ perft 5 8604788 perft 6 299491047 id 295 -epd qb1r1krn/pppp2pp/1n2ppb1/4P3/7P/8/PPPP1PP1/QBNRBKRN w GDgd - 0 9 +epd qb1r1krn/pppp2pp/1n2ppb1/4P3/7P/8/PPPP1PP1/QBNRBKRN w GDgd - perft 1 20 perft 2 578 perft 3 12205 @@ -2666,7 +2666,7 @@ perft 5 7939483 perft 6 229142178 id 296 -epd qnr1bkrn/p3pppp/1bpp4/1p6/2P2PP1/8/PP1PPN1P/QNRBBKR1 w GCgc - 0 9 +epd qnr1bkrn/p3pppp/1bpp4/1p6/2P2PP1/8/PP1PPN1P/QNRBBKR1 w GCgc - perft 1 30 perft 2 865 perft 3 26617 @@ -2675,7 +2675,7 @@ perft 5 24475596 perft 6 719842237 id 297 -epd 1nkrbbrn/qppppppp/8/8/p2P4/1P5P/P1P1PPP1/QNKRBBRN w - - 0 9 +epd 1nkrbbrn/qppppppp/8/8/p2P4/1P5P/P1P1PPP1/QNKRBBRN w - - perft 1 27 perft 2 672 perft 3 18371 @@ -2684,7 +2684,7 @@ perft 5 14065717 perft 6 410130412 id 298 -epd 1qrkbrnb/ppp1p1pp/n2p4/5p2/4N3/8/PPPPPPPP/Q1RKBRNB w Ffc - 2 9 +epd 1qrkbrnb/ppp1p1pp/n2p4/5p2/4N3/8/PPPPPPPP/Q1RKBRNB w Ffc - perft 1 25 perft 2 718 perft 3 18573 @@ -2693,7 +2693,7 @@ perft 5 14404324 perft 6 424279467 id 299 -epd q1nrkrbn/pp1pppp1/2p4p/8/P7/5Pb1/BPPPPNPP/Q1NRKRB1 w FDfd - 0 9 +epd q1nrkrbn/pp1pppp1/2p4p/8/P7/5Pb1/BPPPPNPP/Q1NRKRB1 w FDfd - perft 1 22 perft 2 558 perft 3 12911 @@ -2702,7 +2702,7 @@ perft 5 8516966 perft 6 228074630 id 300 -epd qnrbkrbn/1p1p1pp1/p1p5/4p2p/8/3P1P2/PPP1P1PP/QNRBKRBN w FCfc - 0 9 +epd qnrbkrbn/1p1p1pp1/p1p5/4p2p/8/3P1P2/PPP1P1PP/QNRBKRBN w FCfc - perft 1 28 perft 2 669 perft 3 17713 @@ -2711,7 +2711,7 @@ perft 5 12055174 perft 6 313276304 id 301 -epd qnrkr1bn/p1pp1ppp/8/1p2p3/3P1P2/bP4P1/P1P1P2P/QNRKRBBN w ECec - 1 9 +epd qnrkr1bn/p1pp1ppp/8/1p2p3/3P1P2/bP4P1/P1P1P2P/QNRKRBBN w ECec - perft 1 23 perft 2 845 perft 3 20973 @@ -2720,7 +2720,7 @@ perft 5 19939053 perft 6 718075943 id 302 -epd q1krrnbb/p1p1pppp/2np4/1pB5/5P2/8/PPPPP1PP/QNRKRN1B w EC - 0 9 +epd q1krrnbb/p1p1pppp/2np4/1pB5/5P2/8/PPPPP1PP/QNRKRN1B w EC - perft 1 29 perft 2 776 perft 3 21966 @@ -2729,7 +2729,7 @@ perft 5 18110831 perft 6 549019739 id 303 -epd bbn1rkrn/pp1p1ppp/8/2p1p1q1/6P1/P7/BPPPPP1P/B1NQRKRN w GEge - 0 9 +epd bbn1rkrn/pp1p1ppp/8/2p1p1q1/6P1/P7/BPPPPP1P/B1NQRKRN w GEge - perft 1 26 perft 2 936 perft 3 25177 @@ -2738,7 +2738,7 @@ perft 5 24984621 perft 6 901444251 id 304 -epd bn1brkrn/pp1qpp1p/2p3p1/3p4/1PPP4/P7/4PPPP/BNQBRKRN w GEge - 1 9 +epd bn1brkrn/pp1qpp1p/2p3p1/3p4/1PPP4/P7/4PPPP/BNQBRKRN w GEge - perft 1 29 perft 2 755 perft 3 22858 @@ -2747,7 +2747,7 @@ perft 5 20128587 perft 6 600207069 id 305 -epd b2rkbrn/p1pppppp/qp6/8/1n6/2B2P2/P1PPP1PP/1NQRKBRN w GDgd - 0 9 +epd b2rkbrn/p1pppppp/qp6/8/1n6/2B2P2/P1PPP1PP/1NQRKBRN w GDgd - perft 1 24 perft 2 878 perft 3 21440 @@ -2756,7 +2756,7 @@ perft 5 20840078 perft 6 775795187 id 306 -epd b2rkrnb/pqp1pppp/n7/1p1p4/P7/N1P2N2/1P1PPPPP/B1QRKR1B w FDfd - 4 9 +epd b2rkrnb/pqp1pppp/n7/1p1p4/P7/N1P2N2/1P1PPPPP/B1QRKR1B w FDfd - perft 1 26 perft 2 724 perft 3 19558 @@ -2765,7 +2765,7 @@ perft 5 16109522 perft 6 492933398 id 307 -epd 1bbqrkrn/ppppp1p1/8/5p1p/P1n3P1/3P4/1PP1PP1P/NBBQRRKN w ge - 1 9 +epd 1bbqrkrn/ppppp1p1/8/5p1p/P1n3P1/3P4/1PP1PP1P/NBBQRRKN w ge - perft 1 25 perft 2 678 perft 3 17351 @@ -2774,7 +2774,7 @@ perft 5 12173245 perft 6 329661421 id 308 -epd nqb1rrkn/ppp1bppp/3pp3/8/3P4/1P6/PQP1PPPP/N1BBRRKN w - - 1 9 +epd nqb1rrkn/ppp1bppp/3pp3/8/3P4/1P6/PQP1PPPP/N1BBRRKN w - - perft 1 23 perft 2 503 perft 3 12465 @@ -2783,7 +2783,7 @@ perft 5 7626054 perft 6 188215608 id 309 -epd nqbrkbr1/p1pppppp/1p6/2N2n2/2P5/5P2/PP1PP1PP/1QBRKBRN w GDgd - 1 9 +epd nqbrkbr1/p1pppppp/1p6/2N2n2/2P5/5P2/PP1PP1PP/1QBRKBRN w GDgd - perft 1 29 perft 2 688 perft 3 20289 @@ -2792,7 +2792,7 @@ perft 5 15167248 perft 6 399015237 id 310 -epd nqbrkrn1/1ppppp2/6pp/p7/1P6/2Q5/P1PPPPPP/N1BRKRNB w FDfd - 0 9 +epd nqbrkrn1/1ppppp2/6pp/p7/1P6/2Q5/P1PPPPPP/N1BRKRNB w FDfd - perft 1 36 perft 2 602 perft 3 20985 @@ -2801,7 +2801,7 @@ perft 5 13706856 perft 6 291708797 id 311 -epd nbqrbrkn/pp1p1pp1/2p5/4p2p/2P3P1/1P3P2/P2PP2P/NBQRBKRN w GD - 0 9 +epd nbqrbrkn/pp1p1pp1/2p5/4p2p/2P3P1/1P3P2/P2PP2P/NBQRBKRN w GD - perft 1 34 perft 2 655 perft 3 22581 @@ -2810,7 +2810,7 @@ perft 5 16613630 perft 6 379344541 id 312 -epd nqrbbrkn/1p1pppp1/8/p1p4p/4P2P/1N4P1/PPPP1P2/1QRBBKRN w GC - 0 9 +epd nqrbbrkn/1p1pppp1/8/p1p4p/4P2P/1N4P1/PPPP1P2/1QRBBKRN w GC - perft 1 23 perft 2 597 perft 3 14468 @@ -2819,7 +2819,7 @@ perft 5 10096863 perft 6 294900903 id 313 -epd nqrkbbrn/2p1p1pp/pp1p1p2/8/P2N4/2P5/1P1PPPPP/1QRKBBRN w GCgc - 0 9 +epd nqrkbbrn/2p1p1pp/pp1p1p2/8/P2N4/2P5/1P1PPPPP/1QRKBBRN w GCgc - perft 1 32 perft 2 744 perft 3 23310 @@ -2828,7 +2828,7 @@ perft 5 17597164 perft 6 428786656 id 314 -epd n1krbrnb/q1pppppp/p7/1p6/3Q4/2P2P2/PP1PP1PP/N1RKBRNB w FC - 1 9 +epd n1krbrnb/q1pppppp/p7/1p6/3Q4/2P2P2/PP1PP1PP/N1RKBRNB w FC - perft 1 43 perft 2 1038 perft 3 41327 @@ -2837,7 +2837,7 @@ perft 5 40918952 perft 6 1126603824 id 315 -epd nb1rkrbn/p1pp1p1p/qp6/4p1p1/5PP1/P7/1PPPPB1P/NBQRKR1N w FDfd - 2 9 +epd nb1rkrbn/p1pp1p1p/qp6/4p1p1/5PP1/P7/1PPPPB1P/NBQRKR1N w FDfd - perft 1 26 perft 2 645 perft 3 16463 @@ -2846,7 +2846,7 @@ perft 5 11911314 perft 6 342563372 id 316 -epd nqr1krbn/pppp1ppp/8/8/3pP3/5P2/PPPb1NPP/NQRBKRB1 w FCfc - 3 9 +epd nqr1krbn/pppp1ppp/8/8/3pP3/5P2/PPPb1NPP/NQRBKRB1 w FCfc - perft 1 2 perft 2 51 perft 3 1047 @@ -2855,7 +2855,7 @@ perft 5 612305 perft 6 17040200 id 317 -epd n1rkrbbn/pqppppp1/7p/1p6/8/1NPP4/PP1KPPPP/1QR1RBBN w ec - 0 9 +epd n1rkrbbn/pqppppp1/7p/1p6/8/1NPP4/PP1KPPPP/1QR1RBBN w ec - perft 1 25 perft 2 674 perft 3 17553 @@ -2864,7 +2864,7 @@ perft 5 13421727 perft 6 403551903 id 318 -epd 1qrkrnbb/1p1p1ppp/pnp1p3/8/3PP3/P6P/1PP2PP1/NQRKRNBB w ECec - 0 9 +epd 1qrkrnbb/1p1p1ppp/pnp1p3/8/3PP3/P6P/1PP2PP1/NQRKRNBB w ECec - perft 1 24 perft 2 688 perft 3 17342 @@ -2873,7 +2873,7 @@ perft 5 13322502 perft 6 403441498 id 319 -epd 1bnrqkrn/2ppppp1/p7/1p1b3p/3PP1P1/8/PPPQ1P1P/BBNR1KRN w GDgd - 1 9 +epd 1bnrqkrn/2ppppp1/p7/1p1b3p/3PP1P1/8/PPPQ1P1P/BBNR1KRN w GDgd - perft 1 35 perft 2 925 perft 3 32238 @@ -2882,7 +2882,7 @@ perft 5 30458921 perft 6 824344087 id 320 -epd bnrbqkr1/ppp2pp1/6n1/3pp2p/1P6/2N3N1/P1PPPPPP/B1RBQRK1 w gc - 0 9 +epd bnrbqkr1/ppp2pp1/6n1/3pp2p/1P6/2N3N1/P1PPPPPP/B1RBQRK1 w gc - perft 1 23 perft 2 704 perft 3 17345 @@ -2891,7 +2891,7 @@ perft 5 14154852 perft 6 450893738 id 321 -epd 1nrqkbrn/p1pppppp/8/1p1b4/P6P/5P2/1PPPP1P1/BNRQKBRN w GCgc - 1 9 +epd 1nrqkbrn/p1pppppp/8/1p1b4/P6P/5P2/1PPPP1P1/BNRQKBRN w GCgc - perft 1 19 perft 2 505 perft 3 10619 @@ -2900,7 +2900,7 @@ perft 5 6450025 perft 6 175593967 id 322 -epd b1rqkrnb/ppppppp1/8/6p1/3n4/NP6/P1PPPP1P/B1RQKRNB w FCfc - 0 9 +epd b1rqkrnb/ppppppp1/8/6p1/3n4/NP6/P1PPPP1P/B1RQKRNB w FCfc - perft 1 25 perft 2 614 perft 3 15578 @@ -2909,7 +2909,7 @@ perft 5 10391021 perft 6 259629603 id 323 -epd nbbrqkrn/ppp3p1/3pp3/5p1p/1P2P3/P7/2PPQPPP/NBBR1KRN w GDgd - 0 9 +epd nbbrqkrn/ppp3p1/3pp3/5p1p/1P2P3/P7/2PPQPPP/NBBR1KRN w GDgd - perft 1 30 perft 2 833 perft 3 25719 @@ -2918,7 +2918,7 @@ perft 5 22873901 perft 6 649556666 id 324 -epd nr1bqrk1/ppp1pppp/6n1/3pP3/8/5PQb/PPPP2PP/NRBB1KRN w GB - 3 9 +epd nr1bqrk1/ppp1pppp/6n1/3pP3/8/5PQb/PPPP2PP/NRBB1KRN w GB - perft 1 26 perft 2 734 perft 3 20161 @@ -2927,7 +2927,7 @@ perft 5 17199594 perft 6 512134836 id 325 -epd 1rbqkbr1/ppppp1pp/1n6/4np2/3P1P2/6P1/PPPQP2P/NRB1KBRN w GBgb - 1 9 +epd 1rbqkbr1/ppppp1pp/1n6/4np2/3P1P2/6P1/PPPQP2P/NRB1KBRN w GBgb - perft 1 27 perft 2 662 perft 3 17897 @@ -2936,7 +2936,7 @@ perft 5 13038519 perft 6 338365642 id 326 -epd nr1qkr1b/ppp1pp1p/4bn2/3p2p1/4P3/1Q6/PPPP1PPP/NRB1KRNB w FBfb - 4 9 +epd nr1qkr1b/ppp1pp1p/4bn2/3p2p1/4P3/1Q6/PPPP1PPP/NRB1KRNB w FBfb - perft 1 33 perft 2 939 perft 3 30923 @@ -2945,7 +2945,7 @@ perft 5 30995969 perft 6 991509814 id 327 -epd nb1qbkrn/pprp1pp1/7p/2p1pB2/Q1PP4/8/PP2PPPP/N1R1BKRN w GCg - 2 9 +epd nb1qbkrn/pprp1pp1/7p/2p1pB2/Q1PP4/8/PP2PPPP/N1R1BKRN w GCg - perft 1 47 perft 2 1128 perft 3 50723 @@ -2954,7 +2954,7 @@ perft 5 56747878 perft 6 1560584212 id 328 -epd nrqb1rkn/pp2pppp/2bp4/2p5/6P1/2P3N1/PP1PPP1P/NRQBBRK1 w - - 3 9 +epd nrqb1rkn/pp2pppp/2bp4/2p5/6P1/2P3N1/PP1PPP1P/NRQBBRK1 w - - perft 1 24 perft 2 828 perft 3 21148 @@ -2963,7 +2963,7 @@ perft 5 19506135 perft 6 668969549 id 329 -epd nrq1bbrn/ppkpp2p/2p3p1/P4p2/8/4P1N1/1PPP1PPP/NRQKBBR1 w GB - 0 9 +epd nrq1bbrn/ppkpp2p/2p3p1/P4p2/8/4P1N1/1PPP1PPP/NRQKBBR1 w GB - perft 1 25 perft 2 525 perft 3 13533 @@ -2972,7 +2972,7 @@ perft 5 8250997 perft 6 201795680 id 330 -epd Br1kbrn1/pqpppp2/8/6pp/3b2P1/1N6/PPPPPP1P/1RQKBRN1 w FBfb - 3 9 +epd Br1kbrn1/pqpppp2/8/6pp/3b2P1/1N6/PPPPPP1P/1RQKBRN1 w FBfb - perft 1 20 perft 2 790 perft 3 18175 @@ -2981,7 +2981,7 @@ perft 5 17735648 perft 6 669854148 id 331 -epd nbrqkrbn/2p1p1pp/p7/1p1p1p2/4P1P1/5P2/PPPP3P/NBRQKRBN w FCfc - 0 9 +epd nbrqkrbn/2p1p1pp/p7/1p1p1p2/4P1P1/5P2/PPPP3P/NBRQKRBN w FCfc - perft 1 29 perft 2 771 perft 3 22489 @@ -2990,7 +2990,7 @@ perft 5 19192982 perft 6 591335970 id 332 -epd 1rqbkrbn/1ppppp1p/1n6/p1N3p1/8/2P4P/PP1PPPP1/1RQBKRBN w FBfb - 0 9 +epd 1rqbkrbn/1ppppp1p/1n6/p1N3p1/8/2P4P/PP1PPPP1/1RQBKRBN w FBfb - perft 1 29 perft 2 502 perft 3 14569 @@ -2999,7 +2999,7 @@ perft 5 8652810 perft 6 191762235 id 333 -epd 1rqkrbbn/ppnpp1pp/8/2p5/6p1/3P4/PPP1PPPP/NRK1RBBN w eb - 0 9 +epd 1rqkrbbn/ppnpp1pp/8/2p5/6p1/3P4/PPP1PPPP/NRK1RBBN w eb - perft 1 19 perft 2 531 perft 3 10812 @@ -3008,7 +3008,7 @@ perft 5 6506674 perft 6 184309316 id 334 -epd nrqkrnbb/p1pp2pp/5p2/4P3/2p5/4N3/PP1PP1PP/NRQKR1BB w EBeb - 0 9 +epd nrqkrnbb/p1pp2pp/5p2/4P3/2p5/4N3/PP1PP1PP/NRQKR1BB w EBeb - perft 1 26 perft 2 800 perft 3 23256 @@ -3017,7 +3017,7 @@ perft 5 23952941 perft 6 809841274 id 335 -epd bbnrkqrn/pp3pp1/4p2p/2pp4/4P1P1/1PB5/P1PP1P1P/1BNRKQRN w GDgd - 0 9 +epd bbnrkqrn/pp3pp1/4p2p/2pp4/4P1P1/1PB5/P1PP1P1P/1BNRKQRN w GDgd - perft 1 33 perft 2 915 perft 3 30536 @@ -3026,7 +3026,7 @@ perft 5 29602610 perft 6 881898159 id 336 -epd bnrbkqr1/1p2pppp/6n1/p1pp4/7P/P3P3/1PPPKPP1/BNRB1QRN w gc - 0 9 +epd bnrbkqr1/1p2pppp/6n1/p1pp4/7P/P3P3/1PPPKPP1/BNRB1QRN w gc - perft 1 19 perft 2 457 perft 3 9332 @@ -3035,7 +3035,7 @@ perft 5 5356253 perft 6 144653627 id 337 -epd b1rkqbrn/pp1p2pp/2n1p3/2p2p2/3P2PP/8/PPP1PP2/BNKRQBRN w gc - 0 9 +epd b1rkqbrn/pp1p2pp/2n1p3/2p2p2/3P2PP/8/PPP1PP2/BNKRQBRN w gc - perft 1 30 perft 2 985 perft 3 30831 @@ -3044,7 +3044,7 @@ perft 5 32684185 perft 6 1080607773 id 338 -epd b1rkqrnb/2ppppp1/np6/p6p/1P6/P2P3P/2P1PPP1/BNRKQRNB w FCfc - 0 9 +epd b1rkqrnb/2ppppp1/np6/p6p/1P6/P2P3P/2P1PPP1/BNRKQRNB w FCfc - perft 1 26 perft 2 692 perft 3 18732 @@ -3053,7 +3053,7 @@ perft 5 14561181 perft 6 413226841 id 339 -epd nbbrkqrn/1ppp1p2/p6p/4p1p1/5P2/1P5P/P1PPPNP1/NBBRKQR1 w GDgd - 0 9 +epd nbbrkqrn/1ppp1p2/p6p/4p1p1/5P2/1P5P/P1PPPNP1/NBBRKQR1 w GDgd - perft 1 22 perft 2 561 perft 3 13222 @@ -3062,7 +3062,7 @@ perft 5 9307003 perft 6 273928315 id 340 -epd nrbbkqrn/p1pppppp/8/1p6/4P3/7Q/PPPP1PPP/NRBBK1RN w GBgb - 0 9 +epd nrbbkqrn/p1pppppp/8/1p6/4P3/7Q/PPPP1PPP/NRBBK1RN w GBgb - perft 1 38 perft 2 769 perft 3 28418 @@ -3071,7 +3071,7 @@ perft 5 23091070 perft 6 560139600 id 341 -epd nrbkqbrn/1pppp2p/8/p4pp1/P4PQ1/8/1PPPP1PP/NRBK1BRN w GBgb - 0 9 +epd nrbkqbrn/1pppp2p/8/p4pp1/P4PQ1/8/1PPPP1PP/NRBK1BRN w GBgb - perft 1 23 perft 2 507 perft 3 13067 @@ -3080,7 +3080,7 @@ perft 5 8887567 perft 6 237475184 id 342 -epd nr1kqr1b/pp2pppp/5n2/2pp4/P5b1/5P2/1PPPPRPP/NRBK1QNB w Bfb - 2 9 +epd nr1kqr1b/pp2pppp/5n2/2pp4/P5b1/5P2/1PPPPRPP/NRBK1QNB w Bfb - perft 1 18 perft 2 626 perft 3 12386 @@ -3089,7 +3089,7 @@ perft 5 9465555 perft 6 335004239 id 343 -epd nbkrbqrn/1pppppp1/8/4P2p/pP6/P7/2PP1PPP/NBRKBQRN w GC - 0 9 +epd nbkrbqrn/1pppppp1/8/4P2p/pP6/P7/2PP1PPP/NBRKBQRN w GC - perft 1 22 perft 2 329 perft 3 8475 @@ -3098,7 +3098,7 @@ perft 5 4160034 perft 6 82875306 id 344 -epd nrkb1qrn/pp1pp1pp/8/5p1b/P1p4P/6N1/1PPPPPP1/NRKBBQR1 w GBgb - 2 9 +epd nrkb1qrn/pp1pp1pp/8/5p1b/P1p4P/6N1/1PPPPPP1/NRKBBQR1 w GBgb - perft 1 16 perft 2 479 perft 3 9037 @@ -3107,7 +3107,7 @@ perft 5 5862341 perft 6 184959796 id 345 -epd 1rkq1brn/ppppp1pp/1n6/3b1p2/3N3P/5P2/PPPPP1P1/1RKQBBRN w GBgb - 3 9 +epd 1rkq1brn/ppppp1pp/1n6/3b1p2/3N3P/5P2/PPPPP1P1/1RKQBBRN w GBgb - perft 1 23 perft 2 614 perft 3 15324 @@ -3116,7 +3116,7 @@ perft 5 11090645 perft 6 313526088 id 346 -epd nrk1brnb/pp1ppppp/2p5/3q4/5P2/PP6/1KPPP1PP/NR1QBRNB w fb - 1 9 +epd nrk1brnb/pp1ppppp/2p5/3q4/5P2/PP6/1KPPP1PP/NR1QBRNB w fb - perft 1 25 perft 2 942 perft 3 21765 @@ -3125,7 +3125,7 @@ perft 5 19318837 perft 6 685549171 id 347 -epd nbrkqr1n/1pppp2p/p4pp1/2Bb4/5P2/6P1/PPPPP2P/NBRKQ1RN w Cfc - 2 9 +epd nbrkqr1n/1pppp2p/p4pp1/2Bb4/5P2/6P1/PPPPP2P/NBRKQ1RN w Cfc - perft 1 30 perft 2 841 perft 3 24775 @@ -3134,7 +3134,7 @@ perft 5 20145765 perft 6 557578726 id 348 -epd n1kbqrbn/2p1pppp/1r6/pp1p4/P7/3P4/1PP1PPPP/NRKBQRBN w FBf - 2 9 +epd n1kbqrbn/2p1pppp/1r6/pp1p4/P7/3P4/1PP1PPPP/NRKBQRBN w FBf - perft 1 21 perft 2 591 perft 3 14101 @@ -3143,7 +3143,7 @@ perft 5 10295086 perft 6 292131422 id 349 -epd nrkqrbb1/ppp1pppp/3p4/8/4P3/2Pn1P2/PP4PP/NRKQRBBN w EBeb - 0 9 +epd nrkqrbb1/ppp1pppp/3p4/8/4P3/2Pn1P2/PP4PP/NRKQRBBN w EBeb - perft 1 4 perft 2 88 perft 3 3090 @@ -3152,7 +3152,7 @@ perft 5 2640555 perft 6 66958031 id 350 -epd nrkqrnbb/ppppp1p1/7p/1P3p2/3P4/2P5/P3PPPP/NRKQRNBB w EBeb - 0 9 +epd nrkqrnbb/ppppp1p1/7p/1P3p2/3P4/2P5/P3PPPP/NRKQRNBB w EBeb - perft 1 29 perft 2 689 perft 3 21091 @@ -3161,7 +3161,7 @@ perft 5 16226660 perft 6 408570219 id 351 -epd bbnr1rqn/pp2pkpp/2pp1p2/8/4P1P1/8/PPPP1P1P/BBNRKRQN w FD - 0 9 +epd bbnr1rqn/pp2pkpp/2pp1p2/8/4P1P1/8/PPPP1P1P/BBNRKRQN w FD - perft 1 21 perft 2 463 perft 3 11135 @@ -3170,7 +3170,7 @@ perft 5 6826249 perft 6 165025370 id 352 -epd bnrbk1qn/1pppprpp/8/p4p1P/6P1/3P4/PPP1PP2/BNRBKRQN w FCc - 0 9 +epd bnrbk1qn/1pppprpp/8/p4p1P/6P1/3P4/PPP1PP2/BNRBKRQN w FCc - perft 1 22 perft 2 459 perft 3 11447 @@ -3179,7 +3179,7 @@ perft 5 7371098 perft 6 190583454 id 353 -epd 1nrkrbqn/p1pp1ppp/4p3/1p6/1PP5/6PB/P2PPPbP/BNRKR1QN w ECec - 0 9 +epd 1nrkrbqn/p1pp1ppp/4p3/1p6/1PP5/6PB/P2PPPbP/BNRKR1QN w ECec - perft 1 30 perft 2 931 perft 3 29012 @@ -3188,7 +3188,7 @@ perft 5 28412902 perft 6 869228014 id 354 -epd b1rkr1nb/pppppqp1/n4B2/7p/8/1P4P1/P1PPPP1P/1NKRRQNB w ec - 1 9 +epd b1rkr1nb/pppppqp1/n4B2/7p/8/1P4P1/P1PPPP1P/1NKRRQNB w ec - perft 1 36 perft 2 934 perft 3 31790 @@ -3197,7 +3197,7 @@ perft 5 30392925 perft 6 952871799 id 355 -epd nbbrkrqn/p1ppp1p1/8/1p3p1p/2P3PP/8/PP1PPPQ1/NBBRKR1N w FDfd - 0 9 +epd nbbrkrqn/p1ppp1p1/8/1p3p1p/2P3PP/8/PP1PPPQ1/NBBRKR1N w FDfd - perft 1 34 perft 2 938 perft 3 31848 @@ -3206,7 +3206,7 @@ perft 5 31185844 perft 6 944483246 id 356 -epd 1rbbkrqn/ppp1pp2/1n1p2p1/7p/P3P1P1/3P4/1PP2P1P/NRBBKRQN w FBfb - 0 9 +epd 1rbbkrqn/ppp1pp2/1n1p2p1/7p/P3P1P1/3P4/1PP2P1P/NRBBKRQN w FBfb - perft 1 26 perft 2 646 perft 3 18083 @@ -3215,7 +3215,7 @@ perft 5 14006203 perft 6 384101783 id 357 -epd nrbkrbq1/Qpppp1pp/2n5/5p2/P4P2/6N1/1PPPP1PP/NRBKRB2 w EBeb - 1 9 +epd nrbkrbq1/Qpppp1pp/2n5/5p2/P4P2/6N1/1PPPP1PP/NRBKRB2 w EBeb - perft 1 27 perft 2 619 perft 3 16713 @@ -3224,7 +3224,7 @@ perft 5 11718463 perft 6 313794027 id 358 -epd 1rbkr1nb/pppp1qpp/1n6/4pp2/1PP1P3/8/PB1P1PPP/NR1KRQNB w EBeb - 1 9 +epd 1rbkr1nb/pppp1qpp/1n6/4pp2/1PP1P3/8/PB1P1PPP/NR1KRQNB w EBeb - perft 1 32 perft 2 1029 perft 3 32970 @@ -3233,7 +3233,7 @@ perft 5 35483796 perft 6 1181835398 id 359 -epd nbrk1rqn/p1ppp2p/1p6/5ppb/8/1N2P2P/PPPP1PP1/1BKRBRQN w fc - 0 9 +epd nbrk1rqn/p1ppp2p/1p6/5ppb/8/1N2P2P/PPPP1PP1/1BKRBRQN w fc - perft 1 18 perft 2 594 perft 3 12350 @@ -3242,7 +3242,7 @@ perft 5 9329122 perft 6 315021712 id 360 -epd nrkbbrqn/3pppp1/7p/ppp5/P7/1N5P/1PPPPPP1/1RKBBRQN w FBfb - 0 9 +epd nrkbbrqn/3pppp1/7p/ppp5/P7/1N5P/1PPPPPP1/1RKBBRQN w FBfb - perft 1 19 perft 2 417 perft 3 9026 @@ -3251,7 +3251,7 @@ perft 5 5236331 perft 6 137024458 id 361 -epd nrkr1bqn/ppp1pppp/3p4/1b6/7P/P7/1PPPPPP1/NRKRBBQN w DBdb - 1 9 +epd nrkr1bqn/ppp1pppp/3p4/1b6/7P/P7/1PPPPPP1/NRKRBBQN w DBdb - perft 1 17 perft 2 457 perft 3 9083 @@ -3260,7 +3260,7 @@ perft 5 5503579 perft 6 150091997 id 362 -epd nrkrbqnb/p4ppp/1p2p3/2pp4/6P1/2P2N2/PPNPPP1P/1RKRBQ1B w DBdb - 0 9 +epd nrkrbqnb/p4ppp/1p2p3/2pp4/6P1/2P2N2/PPNPPP1P/1RKRBQ1B w DBdb - perft 1 27 perft 2 755 perft 3 21012 @@ -3269,7 +3269,7 @@ perft 5 17883987 perft 6 547233320 id 363 -epd nbkrr1bn/ppB2ppp/4p3/2qp4/4P3/5P2/PPPP2PP/NBRKRQ1N w EC - 1 9 +epd nbkrr1bn/ppB2ppp/4p3/2qp4/4P3/5P2/PPPP2PP/NBRKRQ1N w EC - perft 1 37 perft 2 1473 perft 3 51939 @@ -3278,7 +3278,7 @@ perft 5 68070015 perft 6 2490912491 id 364 -epd n1kbrqbn/p1pp1pp1/4p2p/2B5/1r3P2/8/PPPPP1PP/NRKBRQ1N w EBe - 2 9 +epd n1kbrqbn/p1pp1pp1/4p2p/2B5/1r3P2/8/PPPPP1PP/NRKBRQ1N w EBe - perft 1 30 perft 2 1029 perft 3 30874 @@ -3287,7 +3287,7 @@ perft 5 32318550 perft 6 1106487743 id 365 -epd nrkrqbbn/2pppp1p/8/pp6/1P1P2p1/P5P1/2P1PP1P/NRKRQBBN w DBdb - 0 9 +epd nrkrqbbn/2pppp1p/8/pp6/1P1P2p1/P5P1/2P1PP1P/NRKRQBBN w DBdb - perft 1 22 perft 2 421 perft 3 10034 @@ -3296,7 +3296,7 @@ perft 5 5754555 perft 6 141245633 id 366 -epd nrkr1nbb/1ppp2pp/p3q3/4pp2/2P5/P3P3/1PKP1PPP/NR1RQNBB w db - 0 9 +epd nrkr1nbb/1ppp2pp/p3q3/4pp2/2P5/P3P3/1PKP1PPP/NR1RQNBB w db - perft 1 22 perft 2 619 perft 3 13953 @@ -3305,7 +3305,7 @@ perft 5 9905109 perft 6 301403003 id 367 -epd bbnrkrnq/1pp1p2p/6p1/p2p1p2/8/1P2P3/P1PP1PPP/BBNRKRNQ w FDfd - 0 9 +epd bbnrkrnq/1pp1p2p/6p1/p2p1p2/8/1P2P3/P1PP1PPP/BBNRKRNQ w FDfd - perft 1 27 perft 2 805 perft 3 21915 @@ -3314,7 +3314,7 @@ perft 5 19133881 perft 6 620749189 id 368 -epd bnrbkrn1/pp1ppp2/2p3pp/8/2Pq4/P4PP1/1P1PP2P/BNRBKRNQ w FCfc - 1 9 +epd bnrbkrn1/pp1ppp2/2p3pp/8/2Pq4/P4PP1/1P1PP2P/BNRBKRNQ w FCfc - perft 1 20 perft 2 770 perft 3 16593 @@ -3323,7 +3323,7 @@ perft 5 13581691 perft 6 456736500 id 369 -epd b1rkrbnq/1pp1pppp/2np4/p5N1/8/1P2P3/P1PP1PPP/BNRKRB1Q w ECec - 0 9 +epd b1rkrbnq/1pp1pppp/2np4/p5N1/8/1P2P3/P1PP1PPP/BNRKRB1Q w ECec - perft 1 37 perft 2 740 perft 3 27073 @@ -3332,7 +3332,7 @@ perft 5 21156664 perft 6 485803600 id 370 -epd b1krrnqb/pp1ppp1p/n1p3p1/2N5/6P1/8/PPPPPP1P/B1RKRNQB w EC - 0 9 +epd b1krrnqb/pp1ppp1p/n1p3p1/2N5/6P1/8/PPPPPP1P/B1RKRNQB w EC - perft 1 34 perft 2 850 perft 3 28494 @@ -3341,7 +3341,7 @@ perft 5 25360295 perft 6 698159474 id 371 -epd 1bbr1rnq/ppppkppp/8/3np3/4P3/3P4/PPP1KPPP/NBBRR1NQ w - - 1 9 +epd 1bbr1rnq/ppppkppp/8/3np3/4P3/3P4/PPP1KPPP/NBBRR1NQ w - - perft 1 27 perft 2 704 perft 3 18290 @@ -3350,7 +3350,7 @@ perft 5 12817011 perft 6 341026662 id 372 -epd nrbbk1nq/p1p1prpp/1p6/N2p1p2/P7/8/1PPPPPPP/R1BBKRNQ w Fb - 2 9 +epd nrbbk1nq/p1p1prpp/1p6/N2p1p2/P7/8/1PPPPPPP/R1BBKRNQ w Fb - perft 1 23 perft 2 552 perft 3 13710 @@ -3359,7 +3359,7 @@ perft 5 9236564 perft 6 248469879 id 373 -epd 1rbkrb1q/1pppp1pp/1n5n/p4p2/P3P3/1P6/2PPNPPP/NRBKRB1Q w EBeb - 1 9 +epd 1rbkrb1q/1pppp1pp/1n5n/p4p2/P3P3/1P6/2PPNPPP/NRBKRB1Q w EBeb - perft 1 22 perft 2 415 perft 3 10198 @@ -3368,7 +3368,7 @@ perft 5 5735644 perft 6 135295774 id 374 -epd nrbkr1qb/1pp1pppp/6n1/p2p4/2P1P3/1N4N1/PP1P1PPP/1RBKR1QB w EBeb - 0 9 +epd nrbkr1qb/1pp1pppp/6n1/p2p4/2P1P3/1N4N1/PP1P1PPP/1RBKR1QB w EBeb - perft 1 27 perft 2 709 perft 3 19126 @@ -3377,7 +3377,7 @@ perft 5 14192779 perft 6 380516508 id 375 -epd nbrkbrnq/p3p1pp/1pp2p2/3p4/1PP5/4P3/P1KP1PPP/NBR1BRNQ w fc - 0 9 +epd nbrkbrnq/p3p1pp/1pp2p2/3p4/1PP5/4P3/P1KP1PPP/NBR1BRNQ w fc - perft 1 24 perft 2 715 perft 3 18009 @@ -3386,7 +3386,7 @@ perft 5 14322279 perft 6 427269976 id 376 -epd nrk1brnq/pp1p1pp1/7p/b1p1p3/1P6/6P1/P1PPPPQP/NRKBBRN1 w FBfb - 2 9 +epd nrk1brnq/pp1p1pp1/7p/b1p1p3/1P6/6P1/P1PPPPQP/NRKBBRN1 w FBfb - perft 1 29 perft 2 675 perft 3 20352 @@ -3395,7 +3395,7 @@ perft 5 15316285 perft 6 389051744 id 377 -epd nrkr1bnq/1p2pppp/p2p4/1bp5/PP6/1R5N/2PPPPPP/N1KRBB1Q w Ddb - 2 9 +epd nrkr1bnq/1p2pppp/p2p4/1bp5/PP6/1R5N/2PPPPPP/N1KRBB1Q w Ddb - perft 1 27 perft 2 744 perft 3 20494 @@ -3404,7 +3404,7 @@ perft 5 16188945 perft 6 458900901 id 378 -epd nrk1b1qb/pppn1ppp/3rp3/3p4/2P3P1/3P4/PPN1PP1P/1RKRBNQB w DBb - 3 9 +epd nrk1b1qb/pppn1ppp/3rp3/3p4/2P3P1/3P4/PPN1PP1P/1RKRBNQB w DBb - perft 1 35 perft 2 941 perft 3 33203 @@ -3413,7 +3413,7 @@ perft 5 33150360 perft 6 968024386 id 379 -epd nb1rrnbq/ppkp1ppp/8/2p1p3/P7/1N2P3/1PPP1PPP/1BKRRNBQ w - - 1 9 +epd nb1rrnbq/ppkp1ppp/8/2p1p3/P7/1N2P3/1PPP1PPP/1BKRRNBQ w - - perft 1 19 perft 2 451 perft 3 9655 @@ -3422,7 +3422,7 @@ perft 5 5506897 perft 6 139436165 id 380 -epd nrkbrnbq/4pppp/1ppp4/p7/2P1P3/3P2N1/PP3PPP/NRKBR1BQ w EBeb - 0 9 +epd nrkbrnbq/4pppp/1ppp4/p7/2P1P3/3P2N1/PP3PPP/NRKBR1BQ w EBeb - perft 1 29 perft 2 591 perft 3 17132 @@ -3431,7 +3431,7 @@ perft 5 11245508 perft 6 270967202 id 381 -epd nrkrnbbq/3p1ppp/1p6/p1p1p3/3P2P1/P4Q2/1PP1PP1P/NRKRNBB1 w DBdb - 0 9 +epd nrkrnbbq/3p1ppp/1p6/p1p1p3/3P2P1/P4Q2/1PP1PP1P/NRKRNBB1 w DBdb - perft 1 38 perft 2 792 perft 3 28597 @@ -3440,7 +3440,7 @@ perft 5 22654797 perft 6 540864616 id 382 -epd nr1rnqbb/ppp1pp1p/3k2p1/3p4/1P5P/3P1N2/P1P1PPP1/NRKR1QBB w DB - 1 9 +epd nr1rnqbb/ppp1pp1p/3k2p1/3p4/1P5P/3P1N2/P1P1PPP1/NRKR1QBB w DB - perft 1 25 perft 2 758 perft 3 18547 @@ -3449,7 +3449,7 @@ perft 5 13890077 perft 6 402109399 id 383 -epd bbqrnnkr/1ppp1p1p/5p2/p5p1/P7/1P4P1/2PPPP1P/1BQRNNKR w HDhd - 0 9 +epd bbqrnnkr/1ppp1p1p/5p2/p5p1/P7/1P4P1/2PPPP1P/1BQRNNKR w HDhd - perft 1 20 perft 2 322 perft 3 7224 @@ -3458,7 +3458,7 @@ perft 5 3588435 perft 6 82754650 id 384 -epd bqrb2k1/pppppppr/5nnp/8/3P1P2/4P1N1/PPP3PP/BQRBN1KR w HCc - 1 9 +epd bqrb2k1/pppppppr/5nnp/8/3P1P2/4P1N1/PPP3PP/BQRBN1KR w HCc - perft 1 25 perft 2 597 perft 3 15872 @@ -3467,7 +3467,7 @@ perft 5 11162476 perft 6 295682250 id 385 -epd bqrnn1kr/1pppbppp/8/4p3/1p6/2P1N2P/P2PPPP1/BQR1NBKR w HChc - 1 9 +epd bqrnn1kr/1pppbppp/8/4p3/1p6/2P1N2P/P2PPPP1/BQR1NBKR w HChc - perft 1 34 perft 2 921 perft 3 31695 @@ -3476,7 +3476,7 @@ perft 5 30126510 perft 6 850296236 id 386 -epd bqr1nkr1/pppppp2/2n3p1/7p/1P1b1P2/8/PQP1P1PP/B1RNNKRB w GCgc - 0 9 +epd bqr1nkr1/pppppp2/2n3p1/7p/1P1b1P2/8/PQP1P1PP/B1RNNKRB w GCgc - perft 1 23 perft 2 788 perft 3 21539 @@ -3485,7 +3485,7 @@ perft 5 20849374 perft 6 645694580 id 387 -epd qbbrnn1r/1pppp1pk/p7/5p1p/P2P3P/3N4/1PP1PPP1/QBBR1NKR w HD - 0 9 +epd qbbrnn1r/1pppp1pk/p7/5p1p/P2P3P/3N4/1PP1PPP1/QBBR1NKR w HD - perft 1 34 perft 2 713 perft 3 24475 @@ -3494,7 +3494,7 @@ perft 5 19494094 perft 6 482645160 id 388 -epd qrbb2kr/p1pppppp/1p1n4/8/1P3n2/P7/Q1PPP1PP/1RBBNNKR w HBhb - 0 9 +epd qrbb2kr/p1pppppp/1p1n4/8/1P3n2/P7/Q1PPP1PP/1RBBNNKR w HBhb - perft 1 28 perft 2 977 perft 3 26955 @@ -3503,7 +3503,7 @@ perft 5 27802999 perft 6 992109168 id 389 -epd qrb2bkr/1pp1pppp/2np1n2/pN6/3P4/4B3/PPP1PPPP/QR2NBKR w HBhb - 0 9 +epd qrb2bkr/1pp1pppp/2np1n2/pN6/3P4/4B3/PPP1PPPP/QR2NBKR w HBhb - perft 1 27 perft 2 730 perft 3 20534 @@ -3512,7 +3512,7 @@ perft 5 17005916 perft 6 507008968 id 390 -epd qrbnnkrb/pp2pp1p/8/2pp2p1/7P/P1P5/QP1PPPP1/1RBNNKRB w GBgb - 0 9 +epd qrbnnkrb/pp2pp1p/8/2pp2p1/7P/P1P5/QP1PPPP1/1RBNNKRB w GBgb - perft 1 24 perft 2 813 perft 3 21142 @@ -3521,7 +3521,7 @@ perft 5 19615756 perft 6 655850285 id 391 -epd 1brnb1kr/p1pppppp/1p6/8/4q2n/1P2P1P1/PNPP1P1P/QBR1BNKR w HChc - 3 9 +epd 1brnb1kr/p1pppppp/1p6/8/4q2n/1P2P1P1/PNPP1P1P/QBR1BNKR w HChc - perft 1 17 perft 2 734 perft 3 13462 @@ -3530,7 +3530,7 @@ perft 5 11032633 perft 6 416356876 id 392 -epd 1rnbbnkr/1pp1pppp/1q1p4/p7/4P3/5PN1/PPPP1BPP/QRNB2KR w HBhb - 1 9 +epd 1rnbbnkr/1pp1pppp/1q1p4/p7/4P3/5PN1/PPPP1BPP/QRNB2KR w HBhb - perft 1 26 perft 2 809 perft 3 21764 @@ -3539,7 +3539,7 @@ perft 5 20292750 perft 6 675408811 id 393 -epd qrnnbb1Q/ppp1pk1p/3p2p1/5p2/PP6/5P2/2PPP1PP/1RNNBBKR w HB - 0 9 +epd qrnnbb1Q/ppp1pk1p/3p2p1/5p2/PP6/5P2/2PPP1PP/1RNNBBKR w HB - perft 1 37 perft 2 751 perft 3 27902 @@ -3548,7 +3548,7 @@ perft 5 22443036 perft 6 515122176 id 394 -epd qrnnbkrb/p3p1pp/3p1p2/1pp5/PP2P3/8/2PP1PPP/QRNNBRKB w gb - 0 9 +epd qrnnbkrb/p3p1pp/3p1p2/1pp5/PP2P3/8/2PP1PPP/QRNNBRKB w gb - perft 1 30 perft 2 906 perft 3 27955 @@ -3557,7 +3557,7 @@ perft 5 27658191 perft 6 890966633 id 395 -epd qbrnnkbr/1p2pp1p/p1p3p1/3p4/6P1/P1N4P/1PPPPP2/QBR1NKBR w HChc - 0 9 +epd qbrnnkbr/1p2pp1p/p1p3p1/3p4/6P1/P1N4P/1PPPPP2/QBR1NKBR w HChc - perft 1 26 perft 2 701 perft 3 18930 @@ -3566,7 +3566,7 @@ perft 5 14733245 perft 6 416881799 id 396 -epd qr1b1kbr/1p1ppppp/1n1n4/p1p5/4P3/5NPP/PPPP1P2/QRNB1KBR w HBhb - 1 9 +epd qr1b1kbr/1p1ppppp/1n1n4/p1p5/4P3/5NPP/PPPP1P2/QRNB1KBR w HBhb - perft 1 26 perft 2 649 perft 3 17235 @@ -3575,7 +3575,7 @@ perft 5 12367604 perft 6 342165821 id 397 -epd qrnnkb1r/1pppppp1/7p/p4b2/4P3/5P1P/PPPP2PR/QRNNKBB1 w Bhb - 1 9 +epd qrnnkb1r/1pppppp1/7p/p4b2/4P3/5P1P/PPPP2PR/QRNNKBB1 w Bhb - perft 1 34 perft 2 941 perft 3 31720 @@ -3584,7 +3584,7 @@ perft 5 30307554 perft 6 888709821 id 398 -epd qr1nkrbb/p2ppppp/1pp5/8/3Pn3/1NP3P1/PP2PP1P/QR1NKRBB w FBfb - 1 9 +epd qr1nkrbb/p2ppppp/1pp5/8/3Pn3/1NP3P1/PP2PP1P/QR1NKRBB w FBfb - perft 1 19 perft 2 505 perft 3 11107 @@ -3593,7 +3593,7 @@ perft 5 7046501 perft 6 190414579 id 399 -epd bbrqn1kr/1pppp1pp/4n3/5p2/p5P1/3P4/PPP1PPKP/BBRQNN1R w hc - 0 9 +epd bbrqn1kr/1pppp1pp/4n3/5p2/p5P1/3P4/PPP1PPKP/BBRQNN1R w hc - perft 1 24 perft 2 573 perft 3 12963 @@ -3602,7 +3602,7 @@ perft 5 8191054 perft 6 227555387 id 400 -epd brqb1nkr/pppppp1p/8/4N1pn/5P2/6P1/PPPPP2P/BRQB1NKR w HBhb - 0 9 +epd brqb1nkr/pppppp1p/8/4N1pn/5P2/6P1/PPPPP2P/BRQB1NKR w HBhb - perft 1 26 perft 2 550 perft 3 14338 @@ -3611,7 +3611,7 @@ perft 5 8903754 perft 6 223437427 id 401 -epd brqnn1kr/pp3ppp/2pbp3/3p4/8/2NPP3/PPP1BPPP/BRQ1N1KR w HBhb - 0 9 +epd brqnn1kr/pp3ppp/2pbp3/3p4/8/2NPP3/PPP1BPPP/BRQ1N1KR w HBhb - perft 1 27 perft 2 780 perft 3 20760 @@ -3620,7 +3620,7 @@ perft 5 16243731 perft 6 463883447 id 402 -epd brq1nkrb/ppp2ppp/8/n2pp2P/P7/4P3/1PPP1PP1/BRQNNKRB w GBgb - 1 9 +epd brq1nkrb/ppp2ppp/8/n2pp2P/P7/4P3/1PPP1PP1/BRQNNKRB w GBgb - perft 1 17 perft 2 426 perft 3 8295 @@ -3629,7 +3629,7 @@ perft 5 5048497 perft 6 153986034 id 403 -epd rbbqn1kr/pp2p1pp/6n1/2pp1p2/2P4P/P7/BP1PPPP1/R1BQNNKR w HAha - 0 9 +epd rbbqn1kr/pp2p1pp/6n1/2pp1p2/2P4P/P7/BP1PPPP1/R1BQNNKR w HAha - perft 1 27 perft 2 916 perft 3 25798 @@ -3638,7 +3638,7 @@ perft 5 26302461 perft 6 924181432 id 404 -epd 1qbbn1kr/1ppppppp/r3n3/8/p1P5/P7/1P1PPPPP/RQBBNNKR w HAh - 1 9 +epd 1qbbn1kr/1ppppppp/r3n3/8/p1P5/P7/1P1PPPPP/RQBBNNKR w HAh - perft 1 29 perft 2 817 perft 3 24530 @@ -3647,7 +3647,7 @@ perft 5 22147642 perft 6 670707652 id 405 -epd rqbnnbkr/ppp1ppp1/7p/3p4/PP6/7P/1NPPPPP1/RQB1NBKR w HAa - 1 9 +epd rqbnnbkr/ppp1ppp1/7p/3p4/PP6/7P/1NPPPPP1/RQB1NBKR w HAa - perft 1 23 perft 2 572 perft 3 14509 @@ -3656,7 +3656,7 @@ perft 5 10416981 perft 6 288064942 id 406 -epd r1bnnkrb/q1ppp1pp/p7/1p3pB1/2P1P3/3P4/PP3PPP/RQ1NNKRB w GAga - 2 9 +epd r1bnnkrb/q1ppp1pp/p7/1p3pB1/2P1P3/3P4/PP3PPP/RQ1NNKRB w GAga - perft 1 31 perft 2 925 perft 3 27776 @@ -3665,7 +3665,7 @@ perft 5 26316355 perft 6 843078864 id 407 -epd rbqnb1kr/ppppp1pp/5p2/5N2/7P/1n3P2/PPPPP1P1/RBQNB1KR w HAha - 1 9 +epd rbqnb1kr/ppppp1pp/5p2/5N2/7P/1n3P2/PPPPP1P1/RBQNB1KR w HAha - perft 1 32 perft 2 864 perft 3 27633 @@ -3674,7 +3674,7 @@ perft 5 24738875 perft 6 707188107 id 408 -epd rqnbbn1r/ppppppp1/6k1/8/6Pp/2PN4/PP1PPPKP/RQ1BBN1R w - - 0 9 +epd rqnbbn1r/ppppppp1/6k1/8/6Pp/2PN4/PP1PPPKP/RQ1BBN1R w - - perft 1 27 perft 2 566 perft 3 15367 @@ -3683,7 +3683,7 @@ perft 5 9714509 perft 6 234622128 id 409 -epd rqnnbbkr/p1p2pp1/1p1p3p/4p3/4NP2/6P1/PPPPP2P/RQN1BBKR w HAha - 0 9 +epd rqnnbbkr/p1p2pp1/1p1p3p/4p3/4NP2/6P1/PPPPP2P/RQN1BBKR w HAha - perft 1 27 perft 2 631 perft 3 17923 @@ -3692,7 +3692,7 @@ perft 5 13307890 perft 6 356279813 id 410 -epd 1qnnbrkb/rppp1ppp/p3p3/8/4P3/2PP1P2/PP4PP/RQNNBKRB w GA - 1 9 +epd 1qnnbrkb/rppp1ppp/p3p3/8/4P3/2PP1P2/PP4PP/RQNNBKRB w GA - perft 1 24 perft 2 479 perft 3 12135 @@ -3701,7 +3701,7 @@ perft 5 7204345 perft 6 175460841 id 411 -epd rbqnn1br/p1pppk1p/1p4p1/5p2/8/P1P2P2/1PBPP1PP/R1QNNKBR w HA - 0 9 +epd rbqnn1br/p1pppk1p/1p4p1/5p2/8/P1P2P2/1PBPP1PP/R1QNNKBR w HA - perft 1 31 perft 2 756 perft 3 23877 @@ -3710,7 +3710,7 @@ perft 5 20036784 perft 6 554292502 id 412 -epd rqnbnkbr/1ppppp2/p5p1/8/1P4p1/4PP2/P1PP3P/RQNBNKBR w HAha - 0 9 +epd rqnbnkbr/1ppppp2/p5p1/8/1P4p1/4PP2/P1PP3P/RQNBNKBR w HAha - perft 1 24 perft 2 715 perft 3 18536 @@ -3719,7 +3719,7 @@ perft 5 16013189 perft 6 515078271 id 413 -epd rq1nkbbr/1p2pppp/p2n4/2pp4/1P4P1/P2N4/2PPPP1P/RQ1NKBBR w HAha - 1 9 +epd rq1nkbbr/1p2pppp/p2n4/2pp4/1P4P1/P2N4/2PPPP1P/RQ1NKBBR w HAha - perft 1 27 perft 2 694 perft 3 19840 @@ -3728,7 +3728,7 @@ perft 5 16685687 perft 6 494574415 id 414 -epd r1nnkrbb/pp1pppp1/2p3q1/7p/8/1PPP3P/P3PPP1/RQNNKRBB w FAfa - 1 9 +epd r1nnkrbb/pp1pppp1/2p3q1/7p/8/1PPP3P/P3PPP1/RQNNKRBB w FAfa - perft 1 18 perft 2 520 perft 3 10808 @@ -3737,7 +3737,7 @@ perft 5 7508201 perft 6 235103697 id 415 -epd bbrnqk1r/pppp3p/6p1/4pp2/3P2P1/8/PPP1PP1P/BBRN1NKR w HC - 0 9 +epd bbrnqk1r/pppp3p/6p1/4pp2/3P2P1/8/PPP1PP1P/BBRN1NKR w HC - perft 1 22 perft 2 566 perft 3 12965 @@ -3746,7 +3746,7 @@ perft 5 8721079 perft 6 259069471 id 416 -epd brnb1nkr/pppqpp2/3p2pp/8/3PP3/1P6/PBP2PPP/1RNBQNKR w HBhb - 0 9 +epd brnb1nkr/pppqpp2/3p2pp/8/3PP3/1P6/PBP2PPP/1RNBQNKR w HBhb - perft 1 32 perft 2 859 perft 3 28517 @@ -3755,7 +3755,7 @@ perft 5 27734108 perft 6 829785474 id 417 -epd brnq1b1r/ppp1ppkp/3p1np1/8/8/5P1P/PPPPPKPR/BRNQNB2 w - - 0 9 +epd brnq1b1r/ppp1ppkp/3p1np1/8/8/5P1P/PPPPPKPR/BRNQNB2 w - - perft 1 21 perft 2 511 perft 3 10951 @@ -3764,7 +3764,7 @@ perft 5 6372681 perft 6 167139732 id 418 -epd brnq1rkb/1pppppp1/3n3p/p7/8/P4NP1/1PPPPPRP/BRNQ1K1B w B - 0 9 +epd brnq1rkb/1pppppp1/3n3p/p7/8/P4NP1/1PPPPPRP/BRNQ1K1B w B - perft 1 25 perft 2 548 perft 3 14049 @@ -3773,7 +3773,7 @@ perft 5 9015901 perft 6 235249649 id 419 -epd rbb1qnkr/p1ppp1pp/1p3p2/6n1/8/1PN1P2P/P1PP1PP1/RBB1QNKR w HAha - 0 9 +epd rbb1qnkr/p1ppp1pp/1p3p2/6n1/8/1PN1P2P/P1PP1PP1/RBB1QNKR w HAha - perft 1 25 perft 2 673 perft 3 16412 @@ -3782,7 +3782,7 @@ perft 5 12099119 perft 6 361714466 id 420 -epd rnbb1nkr/1ppp1ppp/4p3/p5q1/6P1/1PP5/PB1PPP1P/RN1BQNKR w HAha - 1 9 +epd rnbb1nkr/1ppp1ppp/4p3/p5q1/6P1/1PP5/PB1PPP1P/RN1BQNKR w HAha - perft 1 19 perft 2 663 perft 3 14149 @@ -3791,7 +3791,7 @@ perft 5 11491355 perft 6 399135495 id 421 -epd rnbqnbkr/1pp1p2p/3p1p2/p5p1/5PP1/2P5/PPNPP2P/RNBQ1BKR w HAha - 0 9 +epd rnbqnbkr/1pp1p2p/3p1p2/p5p1/5PP1/2P5/PPNPP2P/RNBQ1BKR w HAha - perft 1 24 perft 2 647 perft 3 16679 @@ -3800,7 +3800,7 @@ perft 5 12649636 perft 6 361157611 id 422 -epd rnb2krb/pppqppnp/8/3p2p1/1P4P1/7P/P1PPPPB1/RNBQNKR1 w GAga - 1 9 +epd rnb2krb/pppqppnp/8/3p2p1/1P4P1/7P/P1PPPPB1/RNBQNKR1 w GAga - perft 1 24 perft 2 722 perft 3 18749 @@ -3809,7 +3809,7 @@ perft 5 16609220 perft 6 563558512 id 423 -epd rbnqb1kr/pppn1pp1/3p3p/4p3/1P6/P7/R1PPPPPP/1BNQBNKR w Hha - 1 9 +epd rbnqb1kr/pppn1pp1/3p3p/4p3/1P6/P7/R1PPPPPP/1BNQBNKR w Hha - perft 1 20 perft 2 538 perft 3 12277 @@ -3818,7 +3818,7 @@ perft 5 8687621 perft 6 255304141 id 424 -epd rnqb1nkr/p1pbp1pp/8/1pPp1p2/P2P4/8/1P2PPPP/RNQBBNKR w HAha - 1 9 +epd rnqb1nkr/p1pbp1pp/8/1pPp1p2/P2P4/8/1P2PPPP/RNQBBNKR w HAha - perft 1 35 perft 2 764 perft 3 26952 @@ -3827,7 +3827,7 @@ perft 5 22592380 perft 6 564255328 id 425 -epd rnq1bbkr/1p1ppp1p/4n3/p1p3p1/P1PP4/8/RP2PPPP/1NQNBBKR w Hha - 0 9 +epd rnq1bbkr/1p1ppp1p/4n3/p1p3p1/P1PP4/8/RP2PPPP/1NQNBBKR w Hha - perft 1 29 perft 2 709 perft 3 21296 @@ -3836,7 +3836,7 @@ perft 5 17597398 perft 6 506140370 id 426 -epd 1nqnbkrb/1pppp2p/r7/p4pp1/3P4/8/PPPBPPPP/RNQNK1RB w g - 0 9 +epd 1nqnbkrb/1pppp2p/r7/p4pp1/3P4/8/PPPBPPPP/RNQNK1RB w g - perft 1 27 perft 2 1028 perft 3 28534 @@ -3845,7 +3845,7 @@ perft 5 30251988 perft 6 1096869832 id 427 -epd rbnqnkbr/p1pp1p1p/8/1p2p3/3P2pP/2P5/PP2PPP1/RBNQNKBR w HAha - 0 9 +epd rbnqnkbr/p1pp1p1p/8/1p2p3/3P2pP/2P5/PP2PPP1/RBNQNKBR w HAha - perft 1 32 perft 2 832 perft 3 27120 @@ -3854,7 +3854,7 @@ perft 5 24945574 perft 6 724171581 id 428 -epd rnq1nkbr/1p1p1ppp/2p1pb2/p7/7P/2P5/PPNPPPPB/RNQB1K1R w HAha - 2 9 +epd rnq1nkbr/1p1p1ppp/2p1pb2/p7/7P/2P5/PPNPPPPB/RNQB1K1R w HAha - perft 1 31 perft 2 779 perft 3 24010 @@ -3863,7 +3863,7 @@ perft 5 19919434 perft 6 551494771 id 429 -epd rnqnk1br/p1ppp1bp/1p3p2/6p1/4N3/P5P1/1PPPPP1P/R1QNKBBR w HAha - 2 9 +epd rnqnk1br/p1ppp1bp/1p3p2/6p1/4N3/P5P1/1PPPPP1P/R1QNKBBR w HAha - perft 1 25 perft 2 717 perft 3 19396 @@ -3872,7 +3872,7 @@ perft 5 16525239 perft 6 507175842 id 430 -epd rnq1krbb/p1p1pppp/8/1p1p4/1n5B/2N2P2/PPPPP1PP/RNQ1KR1B w FAfa - 0 9 +epd rnq1krbb/p1p1pppp/8/1p1p4/1n5B/2N2P2/PPPPP1PP/RNQ1KR1B w FAfa - perft 1 28 perft 2 867 perft 3 24029 @@ -3881,7 +3881,7 @@ perft 5 21112751 perft 6 654808184 id 431 -epd bbrnnqkr/1pp1pppp/3p4/p7/P3P3/7P/1PPP1PP1/BBRNNQKR w HChc - 0 9 +epd bbrnnqkr/1pp1pppp/3p4/p7/P3P3/7P/1PPP1PP1/BBRNNQKR w HChc - perft 1 24 perft 2 405 perft 3 11025 @@ -3890,7 +3890,7 @@ perft 5 6196438 perft 6 131401224 id 432 -epd brnbnqkr/p1ppp3/1p5p/5Pp1/5P2/3N4/PPPPP2P/BRNB1QKR w HBhb g6 0 9 +epd brnbnqkr/p1ppp3/1p5p/5Pp1/5P2/3N4/PPPPP2P/BRNB1QKR w HBhb g6 perft 1 25 perft 2 785 perft 3 21402 @@ -3899,7 +3899,7 @@ perft 5 20687969 perft 6 695850727 id 433 -epd br1nqbkr/1ppppp2/pn6/6pp/2PP4/1N4P1/PP2PP1P/BR1NQBKR w HBhb - 0 9 +epd br1nqbkr/1ppppp2/pn6/6pp/2PP4/1N4P1/PP2PP1P/BR1NQBKR w HBhb - perft 1 25 perft 2 596 perft 3 16220 @@ -3908,7 +3908,7 @@ perft 5 12185361 perft 6 337805606 id 434 -epd 1rnnqkrb/p2ppp1p/1pp5/2N3p1/8/1P6/P1PPPPKP/BR1NQ1RB w gb - 0 9 +epd 1rnnqkrb/p2ppp1p/1pp5/2N3p1/8/1P6/P1PPPPKP/BR1NQ1RB w gb - perft 1 38 perft 2 960 perft 3 34831 @@ -3917,7 +3917,7 @@ perft 5 32490040 perft 6 880403591 id 435 -epd rbbnnqkr/pp3pp1/2p1p3/3p3p/3P3P/1PP5/P3PPP1/RBBNNQKR w HAha - 0 9 +epd rbbnnqkr/pp3pp1/2p1p3/3p3p/3P3P/1PP5/P3PPP1/RBBNNQKR w HAha - perft 1 30 perft 2 785 perft 3 23079 @@ -3926,7 +3926,7 @@ perft 5 19885037 perft 6 599219582 id 436 -epd rn1bnqkr/p1ppppp1/8/1p5p/P4P1P/3N4/1PPPP1b1/RNBB1QKR w HAha - 0 9 +epd rn1bnqkr/p1ppppp1/8/1p5p/P4P1P/3N4/1PPPP1b1/RNBB1QKR w HAha - perft 1 27 perft 2 752 perft 3 21735 @@ -3935,7 +3935,7 @@ perft 5 18862234 perft 6 547415271 id 437 -epd 1nbnqbkr/1p1p1ppp/r3p3/p1p5/P3P3/3Q4/1PPP1PPP/RNBN1BKR w HAh - 2 9 +epd 1nbnqbkr/1p1p1ppp/r3p3/p1p5/P3P3/3Q4/1PPP1PPP/RNBN1BKR w HAh - perft 1 33 perft 2 721 perft 3 24278 @@ -3944,7 +3944,7 @@ perft 5 19648535 perft 6 496023732 id 438 -epd rnbnqkrb/2pppppp/1p6/p7/1PP5/4N2P/P2PPPP1/RNB1QKRB w GAg - 0 9 +epd rnbnqkrb/2pppppp/1p6/p7/1PP5/4N2P/P2PPPP1/RNB1QKRB w GAg - perft 1 23 perft 2 570 perft 3 14225 @@ -3953,7 +3953,7 @@ perft 5 10022614 perft 6 279545007 id 439 -epd rbnnbq1r/ppppppkp/6p1/N7/4P3/P7/1PPP1PPP/RB1NBQKR w HA - 5 9 +epd rbnnbq1r/ppppppkp/6p1/N7/4P3/P7/1PPP1PPP/RB1NBQKR w HA - perft 1 27 perft 2 620 perft 3 18371 @@ -3962,7 +3962,7 @@ perft 5 13909432 perft 6 349478320 id 440 -epd r1nbbqkr/pppppp1p/8/8/1n3Pp1/3N1QP1/PPPPP2P/RN1BB1KR w HAha - 0 9 +epd r1nbbqkr/pppppp1p/8/8/1n3Pp1/3N1QP1/PPPPP2P/RN1BB1KR w HAha - perft 1 31 perft 2 791 perft 3 25431 @@ -3971,7 +3971,7 @@ perft 5 22408813 perft 6 636779732 id 441 -epd rnq1bbkr/pp1p1ppp/2pnp3/8/7P/1QP5/PP1PPPPR/RNN1BBK1 w Aha - 2 9 +epd rnq1bbkr/pp1p1ppp/2pnp3/8/7P/1QP5/PP1PPPPR/RNN1BBK1 w Aha - perft 1 28 perft 2 559 perft 3 16838 @@ -3980,7 +3980,7 @@ perft 5 12242780 perft 6 315431511 id 442 -epd rnnqbrkb/2ppppp1/1p1N4/p6p/4P3/8/PPPP1PPP/R1NQBKRB w GA - 0 9 +epd rnnqbrkb/2ppppp1/1p1N4/p6p/4P3/8/PPPP1PPP/R1NQBKRB w GA - perft 1 32 perft 2 638 perft 3 20591 @@ -3989,7 +3989,7 @@ perft 5 14395828 perft 6 331782223 id 443 -epd rbnnq1br/pppp1kp1/4pp2/7p/PP6/2PP4/4PPPP/RBNNQKBR w HA - 0 9 +epd rbnnq1br/pppp1kp1/4pp2/7p/PP6/2PP4/4PPPP/RBNNQKBR w HA - perft 1 21 perft 2 521 perft 3 12201 @@ -3998,7 +3998,7 @@ perft 5 8239159 perft 6 227346638 id 444 -epd rnnbqkbr/p2ppp2/7p/1pp3p1/2P2N2/8/PP1PPPPP/RN1BQKBR w HAha - 0 9 +epd rnnbqkbr/p2ppp2/7p/1pp3p1/2P2N2/8/PP1PPPPP/RN1BQKBR w HAha - perft 1 25 perft 2 528 perft 3 13896 @@ -4007,7 +4007,7 @@ perft 5 9079829 perft 6 232750602 id 445 -epd rnn1kbbr/ppppqp2/6p1/2N1p2p/P7/2P5/1P1PPPPP/RN1QKBBR w HAha - 2 9 +epd rnn1kbbr/ppppqp2/6p1/2N1p2p/P7/2P5/1P1PPPPP/RN1QKBBR w HAha - perft 1 27 perft 2 801 perft 3 22088 @@ -4016,7 +4016,7 @@ perft 5 20334071 perft 6 682580976 id 446 -epd rnnqkrbb/p1p1p1pp/1p3p2/8/3p2Q1/P1P1P3/1P1P1PPP/RNN1KRBB w FAfa - 0 9 +epd rnnqkrbb/p1p1p1pp/1p3p2/8/3p2Q1/P1P1P3/1P1P1PPP/RNN1KRBB w FAfa - perft 1 37 perft 2 1014 perft 3 34735 @@ -4025,7 +4025,7 @@ perft 5 32921537 perft 6 988770109 id 447 -epd bbrnk1qr/1pppppp1/p4n1p/8/P2P2N1/8/1PP1PPPP/BBR1NKQR w HC - 1 9 +epd bbrnk1qr/1pppppp1/p4n1p/8/P2P2N1/8/1PP1PPPP/BBR1NKQR w HC - perft 1 21 perft 2 481 perft 3 11213 @@ -4034,7 +4034,7 @@ perft 5 7015419 perft 6 187564853 id 448 -epd brnbnkqr/1pp1p1p1/p2p1p2/7p/1P4PP/8/PBPPPP2/1RNBNKQR w HBhb - 0 9 +epd brnbnkqr/1pp1p1p1/p2p1p2/7p/1P4PP/8/PBPPPP2/1RNBNKQR w HBhb - perft 1 31 perft 2 743 perft 3 24260 @@ -4043,7 +4043,7 @@ perft 5 22391185 perft 6 653721389 id 449 -epd br2kbqr/ppppp1pp/3n1p2/3P4/3n3P/3N4/PPP1PPP1/BR1NKBQR w HBhb - 3 9 +epd br2kbqr/ppppp1pp/3n1p2/3P4/3n3P/3N4/PPP1PPP1/BR1NKBQR w HBhb - perft 1 25 perft 2 872 perft 3 22039 @@ -4052,7 +4052,7 @@ perft 5 20281962 perft 6 685749952 id 450 -epd br1nkqrb/ppppppp1/8/7p/4P3/n1P2PP1/PP1P3P/BRNNKQRB w GBgb - 0 9 +epd br1nkqrb/ppppppp1/8/7p/4P3/n1P2PP1/PP1P3P/BRNNKQRB w GBgb - perft 1 28 perft 2 607 perft 3 16934 @@ -4061,7 +4061,7 @@ perft 5 11607818 perft 6 294181806 id 451 -epd rbbn1kqr/pp1pp1p1/2pn3p/5p2/5P2/1P1N4/PNPPP1PP/RBB2KQR w HAha - 1 9 +epd rbbn1kqr/pp1pp1p1/2pn3p/5p2/5P2/1P1N4/PNPPP1PP/RBB2KQR w HAha - perft 1 27 perft 2 725 perft 3 21543 @@ -4070,7 +4070,7 @@ perft 5 19239812 perft 6 581716972 id 452 -epd rnbbnk1r/pp1ppp1p/6q1/2p5/PP4p1/4P3/2PP1PPP/RNBBNKQR w HAha - 1 9 +epd rnbbnk1r/pp1ppp1p/6q1/2p5/PP4p1/4P3/2PP1PPP/RNBBNKQR w HAha - perft 1 25 perft 2 1072 perft 3 26898 @@ -4079,7 +4079,7 @@ perft 5 28469879 perft 6 1122703887 id 453 -epd rnbnkbqr/1pp3pp/3p4/p3pp2/3P2P1/2N1N3/PPP1PP1P/R1B1KBQR w HAha - 0 9 +epd rnbnkbqr/1pp3pp/3p4/p3pp2/3P2P1/2N1N3/PPP1PP1P/R1B1KBQR w HAha - perft 1 31 perft 2 1028 perft 3 32907 @@ -4088,7 +4088,7 @@ perft 5 36025223 perft 6 1211187800 id 454 -epd r1bnkqrb/1ppppppp/p3n3/8/6P1/4N3/PPPPPPRP/RNB1KQ1B w Aga - 1 9 +epd r1bnkqrb/1ppppppp/p3n3/8/6P1/4N3/PPPPPPRP/RNB1KQ1B w Aga - perft 1 23 perft 2 457 perft 3 11416 @@ -4097,7 +4097,7 @@ perft 5 6666787 perft 6 159759052 id 455 -epd rbn1bkqr/p1pp1pp1/1pn5/4p2p/7P/1PBP4/P1P1PPP1/RBNN1KQR w HAha - 0 9 +epd rbn1bkqr/p1pp1pp1/1pn5/4p2p/7P/1PBP4/P1P1PPP1/RBNN1KQR w HAha - perft 1 23 perft 2 470 perft 3 11649 @@ -4106,7 +4106,7 @@ perft 5 6963287 perft 6 172833738 id 456 -epd rnnbbkqr/3ppppp/p7/1pp5/P6P/6P1/1PPPPP2/RNNBBKQR w HAha - 0 9 +epd rnnbbkqr/3ppppp/p7/1pp5/P6P/6P1/1PPPPP2/RNNBBKQR w HAha - perft 1 26 perft 2 569 perft 3 15733 @@ -4115,7 +4115,7 @@ perft 5 11008114 perft 6 284485303 id 457 -epd r1nk1bqr/1pppp1pp/2n5/p4p1b/5P2/1N4B1/PPPPP1PP/RN1K1BQR w HAha - 2 9 +epd r1nk1bqr/1pppp1pp/2n5/p4p1b/5P2/1N4B1/PPPPP1PP/RN1K1BQR w HAha - perft 1 25 perft 2 824 perft 3 21983 @@ -4124,7 +4124,7 @@ perft 5 20904119 perft 6 716170771 id 458 -epd r1nkbqrb/p2pppp1/npp4p/8/4PP2/2N4P/PPPP2P1/R1NKBQRB w GAga - 0 9 +epd r1nkbqrb/p2pppp1/npp4p/8/4PP2/2N4P/PPPP2P1/R1NKBQRB w GAga - perft 1 31 perft 2 548 perft 3 17480 @@ -4133,7 +4133,7 @@ perft 5 11469548 perft 6 255067638 id 459 -epd rbnnkqbr/ppppp2p/5p2/6p1/2P1B3/P6P/1P1PPPP1/R1NNKQBR w HAha - 1 9 +epd rbnnkqbr/ppppp2p/5p2/6p1/2P1B3/P6P/1P1PPPP1/R1NNKQBR w HAha - perft 1 31 perft 2 809 perft 3 24956 @@ -4142,7 +4142,7 @@ perft 5 21247414 perft 6 606221516 id 460 -epd 1r1bkqbr/pppp1ppp/2nnp3/8/2P5/N4P2/PP1PP1PP/1RNBKQBR w Hh - 0 9 +epd 1r1bkqbr/pppp1ppp/2nnp3/8/2P5/N4P2/PP1PP1PP/1RNBKQBR w Hh - perft 1 28 perft 2 810 perft 3 22844 @@ -4151,7 +4151,7 @@ perft 5 20188622 perft 6 636748147 id 461 -epd rn1kqbbr/p1pppp1p/1p4p1/1n6/1P2P3/4Q2P/P1PP1PP1/RNNK1BBR w HAha - 1 9 +epd rn1kqbbr/p1pppp1p/1p4p1/1n6/1P2P3/4Q2P/P1PP1PP1/RNNK1BBR w HAha - perft 1 39 perft 2 848 perft 3 30100 @@ -4160,7 +4160,7 @@ perft 5 25594662 perft 6 659615710 id 462 -epd rn1kqrbb/pppppppp/8/8/2nP2P1/1P2P3/P1P2P1P/RNNKQRBB w FAfa - 1 9 +epd rn1kqrbb/pppppppp/8/8/2nP2P1/1P2P3/P1P2P1P/RNNKQRBB w FAfa - perft 1 29 perft 2 766 perft 3 21701 @@ -4169,7 +4169,7 @@ perft 5 16944425 perft 6 456898648 id 463 -epd b1rnnkrq/bpppppp1/7p/8/1p6/2B5/PNPPPPPP/1BR1NKRQ w GCgc - 2 9 +epd b1rnnkrq/bpppppp1/7p/8/1p6/2B5/PNPPPPPP/1BR1NKRQ w GCgc - perft 1 25 perft 2 667 perft 3 17253 @@ -4178,7 +4178,7 @@ perft 5 12865247 perft 6 365621294 id 464 -epd brnb1krq/pppppppp/8/5P2/2P1n2P/8/PP1PP1P1/BRNBNKRQ w GBgb - 1 9 +epd brnb1krq/pppppppp/8/5P2/2P1n2P/8/PP1PP1P1/BRNBNKRQ w GBgb - perft 1 23 perft 2 620 perft 3 14882 @@ -4187,7 +4187,7 @@ perft 5 10776855 perft 6 300125003 id 465 -epd b1nnkbrq/pr1pppp1/1p5p/2p5/P2N1P2/8/1PPPP1PP/BR1NKBRQ w GBg - 0 9 +epd b1nnkbrq/pr1pppp1/1p5p/2p5/P2N1P2/8/1PPPP1PP/BR1NKBRQ w GBg - perft 1 24 perft 2 472 perft 3 12181 @@ -4196,7 +4196,7 @@ perft 5 7370758 perft 6 178605165 id 466 -epd br1nkrqb/p1p1p1pp/3n4/1p1p1p2/5N1P/4P3/PPPP1PP1/BR1NKRQB w FBfb - 0 9 +epd br1nkrqb/p1p1p1pp/3n4/1p1p1p2/5N1P/4P3/PPPP1PP1/BR1NKRQB w FBfb - perft 1 24 perft 2 775 perft 3 19398 @@ -4205,7 +4205,7 @@ perft 5 16429837 perft 6 539767605 id 467 -epd rbbnnkrq/p2pp1pp/2p5/5p2/1pPP1B2/P7/1P2PPPP/RB1NNKRQ w GAga - 0 9 +epd rbbnnkrq/p2pp1pp/2p5/5p2/1pPP1B2/P7/1P2PPPP/RB1NNKRQ w GAga - perft 1 34 perft 2 921 perft 3 30474 @@ -4214,7 +4214,7 @@ perft 5 28095833 perft 6 806446436 id 468 -epd rnbbnkr1/1p1ppp1p/2p3p1/p7/2Pq4/1P1P4/P2BPPPP/RN1BNKRQ w GAga - 2 9 +epd rnbbnkr1/1p1ppp1p/2p3p1/p7/2Pq4/1P1P4/P2BPPPP/RN1BNKRQ w GAga - perft 1 26 perft 2 1139 perft 3 29847 @@ -4223,7 +4223,7 @@ perft 5 32825932 perft 6 1281760240 id 469 -epd 1rbnkbrq/pppppp2/n5pp/2P5/P7/4N3/1P1PPPPP/RNB1KBRQ w GAg - 2 9 +epd 1rbnkbrq/pppppp2/n5pp/2P5/P7/4N3/1P1PPPPP/RNB1KBRQ w GAg - perft 1 23 perft 2 574 perft 3 14146 @@ -4232,7 +4232,7 @@ perft 5 10203438 perft 6 301874034 id 470 -epd 1nbnkr1b/rppppppq/p7/7p/1P5P/3P2P1/P1P1PP2/RNBNKRQB w FAf - 1 9 +epd 1nbnkr1b/rppppppq/p7/7p/1P5P/3P2P1/P1P1PP2/RNBNKRQB w FAf - perft 1 33 perft 2 823 perft 3 26696 @@ -4241,7 +4241,7 @@ perft 5 23266182 perft 6 672294132 id 471 -epd rbn1bkrq/ppppp3/4n2p/5pp1/1PN5/2P5/P2PPPPP/RBN1BKRQ w GAga - 0 9 +epd rbn1bkrq/ppppp3/4n2p/5pp1/1PN5/2P5/P2PPPPP/RBN1BKRQ w GAga - perft 1 27 perft 2 859 perft 3 24090 @@ -4250,7 +4250,7 @@ perft 5 23075785 perft 6 789152120 id 472 -epd r1nbbkrq/1ppp2pp/2n2p2/p3p3/5P2/1N4BP/PPPPP1P1/RN1B1KRQ w GAga - 0 9 +epd r1nbbkrq/1ppp2pp/2n2p2/p3p3/5P2/1N4BP/PPPPP1P1/RN1B1KRQ w GAga - perft 1 25 perft 2 774 perft 3 20141 @@ -4259,7 +4259,7 @@ perft 5 16718577 perft 6 515864053 id 473 -epd rnnkbbrq/1pppp1p1/5p2/7p/p6P/3N1P2/PPPPP1PQ/RN1KBBR1 w GAga - 0 9 +epd rnnkbbrq/1pppp1p1/5p2/7p/p6P/3N1P2/PPPPP1PQ/RN1KBBR1 w GAga - perft 1 29 perft 2 673 perft 3 20098 @@ -4268,7 +4268,7 @@ perft 5 15545590 perft 6 416359581 id 474 -epd r1nkbrqb/pppp1p2/n3p1p1/7p/2P2P2/1P6/P2PPQPP/RNNKBR1B w FAfa - 0 9 +epd r1nkbrqb/pppp1p2/n3p1p1/7p/2P2P2/1P6/P2PPQPP/RNNKBR1B w FAfa - perft 1 27 perft 2 722 perft 3 21397 @@ -4277,7 +4277,7 @@ perft 5 18742426 perft 6 537750982 id 475 -epd rbnnkr1q/1ppp2pp/p4p2/P2bp3/4P2P/8/1PPP1PP1/RBNNKRBQ w FAfa - 1 9 +epd rbnnkr1q/1ppp2pp/p4p2/P2bp3/4P2P/8/1PPP1PP1/RBNNKRBQ w FAfa - perft 1 26 perft 2 848 perft 3 23387 @@ -4286,7 +4286,7 @@ perft 5 21591790 perft 6 675163653 id 476 -epd rn1bkrb1/1ppppp1p/pn4p1/8/P2q3P/3P4/NPP1PPP1/RN1BKRBQ w FAfa - 1 9 +epd rn1bkrb1/1ppppp1p/pn4p1/8/P2q3P/3P4/NPP1PPP1/RN1BKRBQ w FAfa - perft 1 22 perft 2 803 perft 3 18322 @@ -4295,7 +4295,7 @@ perft 5 15847763 perft 6 536419559 id 477 -epd rn1krbbq/pppp1npp/4pp2/8/4P2P/3P2P1/PPP2P2/RNNKRBBQ w EAea - 1 9 +epd rn1krbbq/pppp1npp/4pp2/8/4P2P/3P2P1/PPP2P2/RNNKRBBQ w EAea - perft 1 29 perft 2 810 perft 3 23968 @@ -4304,7 +4304,7 @@ perft 5 20361517 perft 6 575069358 id 478 -epd rnn1rqbb/ppkp1pp1/2p1p2p/2P5/8/3P1P2/PP2P1PP/RNNKRQBB w EA - 0 9 +epd rnn1rqbb/ppkp1pp1/2p1p2p/2P5/8/3P1P2/PP2P1PP/RNNKRQBB w EA - perft 1 22 perft 2 506 perft 3 11973 @@ -4313,7 +4313,7 @@ perft 5 7287368 perft 6 189865944 id 479 -epd bbqr1knr/pppppp1p/8/4n1p1/2P1P3/6P1/PPQP1P1P/BB1RNKNR w HDhd - 0 9 +epd bbqr1knr/pppppp1p/8/4n1p1/2P1P3/6P1/PPQP1P1P/BB1RNKNR w HDhd - perft 1 26 perft 2 650 perft 3 18253 @@ -4322,7 +4322,7 @@ perft 5 14301029 perft 6 394943978 id 480 -epd bq1bnknr/pprppp1p/8/2p3p1/4PPP1/8/PPPP3P/BQRBNKNR w HCh - 0 9 +epd bq1bnknr/pprppp1p/8/2p3p1/4PPP1/8/PPPP3P/BQRBNKNR w HCh - perft 1 24 perft 2 548 perft 3 14021 @@ -4331,7 +4331,7 @@ perft 5 9374021 perft 6 250988458 id 481 -epd bqrnkb1r/1p2pppp/p1pp3n/5Q2/2P4P/5N2/PP1PPPP1/B1RNKB1R w HChc - 0 9 +epd bqrnkb1r/1p2pppp/p1pp3n/5Q2/2P4P/5N2/PP1PPPP1/B1RNKB1R w HChc - perft 1 46 perft 2 823 perft 3 33347 @@ -4340,7 +4340,7 @@ perft 5 26130444 perft 6 582880996 id 482 -epd bq1rknrb/pppppp1p/4n3/6p1/4P1P1/3P1P2/PPP4P/BQRNKNRB w GCg - 0 9 +epd bq1rknrb/pppppp1p/4n3/6p1/4P1P1/3P1P2/PPP4P/BQRNKNRB w GCg - perft 1 23 perft 2 618 perft 3 14815 @@ -4349,7 +4349,7 @@ perft 5 10606831 perft 6 315124518 id 483 -epd q1brnknr/pp1pp1p1/8/2p2p1p/5b2/P4N2/1PPPP1PP/QBBRK1NR w hd - 0 9 +epd q1brnknr/pp1pp1p1/8/2p2p1p/5b2/P4N2/1PPPP1PP/QBBRK1NR w hd - perft 1 22 perft 2 675 perft 3 15778 @@ -4358,7 +4358,7 @@ perft 5 12077228 perft 6 368479752 id 484 -epd qrbbnknr/1p1ppp1p/p1p5/8/1P2P1p1/3P1B2/P1P2PPP/QRB1NKNR w HBhb - 0 9 +epd qrbbnknr/1p1ppp1p/p1p5/8/1P2P1p1/3P1B2/P1P2PPP/QRB1NKNR w HBhb - perft 1 32 perft 2 722 perft 3 24049 @@ -4367,7 +4367,7 @@ perft 5 19584539 perft 6 484814878 id 485 -epd qrb1kbnr/p3pppp/2n5/1ppp4/7P/3P1P2/PPP1P1PR/QRBNKBN1 w Bhb - 0 9 +epd qrb1kbnr/p3pppp/2n5/1ppp4/7P/3P1P2/PPP1P1PR/QRBNKBN1 w Bhb - perft 1 26 perft 2 831 perft 3 22606 @@ -4376,7 +4376,7 @@ perft 5 20500804 perft 6 662608969 id 486 -epd qrbnknrb/ppp1pp2/6p1/7p/PPNp4/8/2PPPPPP/QRB1KNRB w GBgb - 0 9 +epd qrbnknrb/ppp1pp2/6p1/7p/PPNp4/8/2PPPPPP/QRB1KNRB w GBgb - perft 1 31 perft 2 840 perft 3 26762 @@ -4385,7 +4385,7 @@ perft 5 24422614 perft 6 701363800 id 487 -epd qbrnbknr/pp1pp1pp/8/2p2p2/3Q4/PP6/2PPPPPP/1BRNBKNR w HChc - 0 9 +epd qbrnbknr/pp1pp1pp/8/2p2p2/3Q4/PP6/2PPPPPP/1BRNBKNR w HChc - perft 1 38 perft 2 1121 perft 3 39472 @@ -4394,7 +4394,7 @@ perft 5 41108769 perft 6 1285503872 id 488 -epd qr1bbk1r/pppppp1p/1n6/5np1/4B3/1PP5/P2PPPPP/QRN1BKNR w HBhb - 0 9 +epd qr1bbk1r/pppppp1p/1n6/5np1/4B3/1PP5/P2PPPPP/QRN1BKNR w HBhb - perft 1 25 perft 2 694 perft 3 16938 @@ -4403,7 +4403,7 @@ perft 5 12164609 perft 6 345122090 id 489 -epd qrnkbbnr/1p1pp2p/p7/2p1Npp1/6P1/7P/PPPPPP2/QR1KBBNR w HBhb - 0 9 +epd qrnkbbnr/1p1pp2p/p7/2p1Npp1/6P1/7P/PPPPPP2/QR1KBBNR w HBhb - perft 1 27 perft 2 586 perft 3 16348 @@ -4412,7 +4412,7 @@ perft 5 11409633 perft 6 298054792 id 490 -epd qrnkbnrb/pp1p1p2/2p1p1pp/4N3/P4P2/8/1PPPP1PP/QR1KBNRB w GBgb - 0 9 +epd qrnkbnrb/pp1p1p2/2p1p1pp/4N3/P4P2/8/1PPPP1PP/QR1KBNRB w GBgb - perft 1 32 perft 2 645 perft 3 20737 @@ -4421,7 +4421,7 @@ perft 5 15037464 perft 6 358531599 id 491 -epd qbrnknbr/1pppppp1/p6p/8/1P6/3PP3/PQP2PPP/1BRNKNBR w HChc - 3 9 +epd qbrnknbr/1pppppp1/p6p/8/1P6/3PP3/PQP2PPP/1BRNKNBR w HChc - perft 1 26 perft 2 595 perft 3 16755 @@ -4430,7 +4430,7 @@ perft 5 12214768 perft 6 323518628 id 492 -epd qrnbk1br/1ppppp1p/p5p1/8/4Pn2/4K1P1/PPPP1P1P/QRNB1NBR w hb - 0 9 +epd qrnbk1br/1ppppp1p/p5p1/8/4Pn2/4K1P1/PPPP1P1P/QRNB1NBR w hb - perft 1 24 perft 2 609 perft 3 13776 @@ -4439,7 +4439,7 @@ perft 5 8538539 perft 6 230364479 id 493 -epd qrnk1bbr/1pnp1ppp/p1p1p3/8/3Q4/1P1N3P/P1PPPPP1/1RNK1BBR w HBhb - 0 9 +epd qrnk1bbr/1pnp1ppp/p1p1p3/8/3Q4/1P1N3P/P1PPPPP1/1RNK1BBR w HBhb - perft 1 43 perft 2 1106 perft 3 42898 @@ -4448,7 +4448,7 @@ perft 5 41695761 perft 6 1113836402 id 494 -epd qrnknrb1/pppppp2/8/6pp/4P2P/3P1P2/PbP3P1/QRNKNRBB w FBfb - 0 9 +epd qrnknrb1/pppppp2/8/6pp/4P2P/3P1P2/PbP3P1/QRNKNRBB w FBfb - perft 1 24 perft 2 658 perft 3 17965 @@ -4457,7 +4457,7 @@ perft 5 14457245 perft 6 400971226 id 495 -epd bbrqnrk1/ppp2ppp/7n/3pp3/8/P4N1N/1PPPPPPP/BBRQ1RK1 w - - 1 9 +epd bbrqnrk1/ppp2ppp/7n/3pp3/8/P4N1N/1PPPPPPP/BBRQ1RK1 w - - perft 1 22 perft 2 503 perft 3 12078 @@ -4466,7 +4466,7 @@ perft 5 8080951 perft 6 224960353 id 496 -epd brqbnk1r/1ppp1ppp/8/p3pn2/8/2PP1P2/PP2PKPP/BRQBN1NR w hb - 1 9 +epd brqbnk1r/1ppp1ppp/8/p3pn2/8/2PP1P2/PP2PKPP/BRQBN1NR w hb - perft 1 25 perft 2 745 perft 3 19387 @@ -4475,7 +4475,7 @@ perft 5 15520298 perft 6 460840861 id 497 -epd brqnkbnr/pp2pp1p/3p4/2p5/5p2/3P3P/PPP1PPP1/B1RNKBNR w Hhb - 0 9 +epd brqnkbnr/pp2pp1p/3p4/2p5/5p2/3P3P/PPP1PPP1/B1RNKBNR w Hhb - perft 1 19 perft 2 516 perft 3 10755 @@ -4484,7 +4484,7 @@ perft 5 6995034 perft 6 214340699 id 498 -epd brq1kn1b/1ppppprp/2n3p1/p7/P1N5/6P1/1PPPPP1P/BRQNK1RB w GBb - 2 9 +epd brq1kn1b/1ppppprp/2n3p1/p7/P1N5/6P1/1PPPPP1P/BRQNK1RB w GBb - perft 1 29 perft 2 557 perft 3 16739 @@ -4493,7 +4493,7 @@ perft 5 10840256 perft 6 249999654 id 499 -epd rbbq1k1r/ppp1pppp/7n/1n1p4/5P2/P2P4/1PPBP1PP/RB1QNKNR w HAha - 1 9 +epd rbbq1k1r/ppp1pppp/7n/1n1p4/5P2/P2P4/1PPBP1PP/RB1QNKNR w HAha - perft 1 25 perft 2 769 perft 3 20110 @@ -4502,7 +4502,7 @@ perft 5 17438715 perft 6 570893953 id 500 -epd r1bbnk1r/qpp1pppp/p6n/3p4/1P6/5N1P/P1PPPPP1/RQBBK1NR w ha - 0 9 +epd r1bbnk1r/qpp1pppp/p6n/3p4/1P6/5N1P/P1PPPPP1/RQBBK1NR w ha - perft 1 23 perft 2 728 perft 3 18209 @@ -4511,7 +4511,7 @@ perft 5 16053564 perft 6 529082811 id 501 -epd rqbnkbnr/1pp2p1p/3p4/p3p1p1/8/2P2P2/PP1PPNPP/RQBNKB1R w HAha - 0 9 +epd rqbnkbnr/1pp2p1p/3p4/p3p1p1/8/2P2P2/PP1PPNPP/RQBNKB1R w HAha - perft 1 26 perft 2 772 perft 3 21903 @@ -4520,7 +4520,7 @@ perft 5 19571559 perft 6 593915677 id 502 -epd r1bnknrb/pqppp1p1/1p5p/5p2/7P/3P2N1/PPP1PPP1/RQBNK1RB w GAga - 2 9 +epd r1bnknrb/pqppp1p1/1p5p/5p2/7P/3P2N1/PPP1PPP1/RQBNK1RB w GAga - perft 1 27 perft 2 748 perft 3 20291 @@ -4529,7 +4529,7 @@ perft 5 16324542 perft 6 506453626 id 503 -epd rbqnbknr/pp1pppp1/8/2p5/3P3p/5N1P/PPP1PPPR/RBQNBK2 w Aha - 0 9 +epd rbqnbknr/pp1pppp1/8/2p5/3P3p/5N1P/PPP1PPPR/RBQNBK2 w Aha - perft 1 30 perft 2 859 perft 3 26785 @@ -4538,7 +4538,7 @@ perft 5 26363334 perft 6 842796987 id 504 -epd rqnbbrk1/ppppppp1/8/5n1p/3P3P/2B3P1/PPP1PP2/RQNB1KNR w HA - 0 9 +epd rqnbbrk1/ppppppp1/8/5n1p/3P3P/2B3P1/PPP1PP2/RQNB1KNR w HA - perft 1 22 perft 2 505 perft 3 11452 @@ -4547,7 +4547,7 @@ perft 5 7055215 perft 6 186760784 id 505 -epd rqnkbbnr/pp2p1p1/8/2pp1p1p/3PPP2/8/PPP1N1PP/RQNKBB1R w HAha - 0 9 +epd rqnkbbnr/pp2p1p1/8/2pp1p1p/3PPP2/8/PPP1N1PP/RQNKBB1R w HAha - perft 1 28 perft 2 832 perft 3 23142 @@ -4556,7 +4556,7 @@ perft 5 20429246 perft 6 663183060 id 506 -epd rqnkbnr1/pppp2bp/6p1/4pp2/1P2P3/3NN3/P1PP1PPP/RQ1KB1RB w GAga - 0 9 +epd rqnkbnr1/pppp2bp/6p1/4pp2/1P2P3/3NN3/P1PP1PPP/RQ1KB1RB w GAga - perft 1 28 perft 2 641 perft 3 18835 @@ -4565,7 +4565,7 @@ perft 5 14038570 perft 6 364210162 id 507 -epd rbq2kbr/pppppppp/2n5/P7/3P1n2/2P5/1P2PPPP/RBQNKNBR w HA - 1 9 +epd rbq2kbr/pppppppp/2n5/P7/3P1n2/2P5/1P2PPPP/RBQNKNBR w HA - perft 1 31 perft 2 889 perft 3 27028 @@ -4574,7 +4574,7 @@ perft 5 24299415 perft 6 692180754 id 508 -epd rq1bkn1r/ppppp2p/3n4/5pp1/2b3P1/1N1P1P2/PPP1P2P/RQ1BKNBR w HAha - 1 9 +epd rq1bkn1r/ppppp2p/3n4/5pp1/2b3P1/1N1P1P2/PPP1P2P/RQ1BKNBR w HAha - perft 1 28 perft 2 810 perft 3 22667 @@ -4583,7 +4583,7 @@ perft 5 18719949 perft 6 556282676 id 509 -epd r1nknbbr/p2ppp1p/1pp3p1/8/1P6/4P3/P1PPNPPq/R1QKNBBR w HAha - 0 9 +epd r1nknbbr/p2ppp1p/1pp3p1/8/1P6/4P3/P1PPNPPq/R1QKNBBR w HAha - perft 1 24 perft 2 797 perft 3 22144 @@ -4592,7 +4592,7 @@ perft 5 21862776 perft 6 716521139 id 510 -epd rqnknrbb/ppp1p3/5ppp/2Np4/2P5/4P3/PP1P1PPP/RQNK1RBB w FAfa - 0 9 +epd rqnknrbb/ppp1p3/5ppp/2Np4/2P5/4P3/PP1P1PPP/RQNK1RBB w FAfa - perft 1 34 perft 2 686 perft 3 23277 @@ -4601,7 +4601,7 @@ perft 5 17664543 perft 6 423574794 id 511 -epd 1brnqknr/2p1pppp/p2p4/1P6/6P1/4Nb2/PP1PPP1P/BBR1QKNR w HChc - 1 9 +epd 1brnqknr/2p1pppp/p2p4/1P6/6P1/4Nb2/PP1PPP1P/BBR1QKNR w HChc - perft 1 34 perft 2 1019 perft 3 32982 @@ -4610,7 +4610,7 @@ perft 5 33322477 perft 6 1043293394 id 512 -epd brn1qknr/1p1pppp1/pb5p/Q1p5/3P3P/8/PPP1PPPR/BRNB1KN1 w Bhb - 2 9 +epd brn1qknr/1p1pppp1/pb5p/Q1p5/3P3P/8/PPP1PPPR/BRNB1KN1 w Bhb - perft 1 32 perft 2 642 perft 3 20952 @@ -4619,7 +4619,7 @@ perft 5 15454749 perft 6 371861782 id 513 -epd brnqkbnr/pppppp2/8/6pp/6P1/P2P1P2/1PP1P2P/BRNQKBNR w HBhb - 0 9 +epd brnqkbnr/pppppp2/8/6pp/6P1/P2P1P2/1PP1P2P/BRNQKBNR w HBhb - perft 1 20 perft 2 441 perft 3 9782 @@ -4628,7 +4628,7 @@ perft 5 5770284 perft 6 153051835 id 514 -epd 2nqknrb/1rpppppp/5B2/pp6/1PP1b3/3P4/P3PPPP/1RNQKNRB w GBg - 1 9 +epd 2nqknrb/1rpppppp/5B2/pp6/1PP1b3/3P4/P3PPPP/1RNQKNRB w GBg - perft 1 35 perft 2 1042 perft 3 36238 @@ -4637,7 +4637,7 @@ perft 5 38505058 perft 6 1202668717 id 515 -epd rb1nqknr/1pp1pppp/8/3p4/p2P4/6PN/PPPQPP1P/RBBN1K1R w HAha - 0 9 +epd rb1nqknr/1pp1pppp/8/3p4/p2P4/6PN/PPPQPP1P/RBBN1K1R w HAha - perft 1 29 perft 2 692 perft 3 21237 @@ -4646,7 +4646,7 @@ perft 5 17820605 perft 6 497251206 id 516 -epd rnbbqknr/pppp4/5p2/4p1pp/P7/2N2PP1/1PPPP2P/R1BBQKNR w HAha - 0 9 +epd rnbbqknr/pppp4/5p2/4p1pp/P7/2N2PP1/1PPPP2P/R1BBQKNR w HAha - perft 1 23 perft 2 595 perft 3 14651 @@ -4655,7 +4655,7 @@ perft 5 10881112 perft 6 329010121 id 517 -epd rn1qkbnr/p1p1pp1p/bp4p1/3p4/1P6/4P3/P1PP1PPP/RNBQKBNR w HAha - 0 9 +epd rn1qkbnr/p1p1pp1p/bp4p1/3p4/1P6/4P3/P1PP1PPP/RNBQKBNR w HAha - perft 1 30 perft 2 794 perft 3 24319 @@ -4664,7 +4664,7 @@ perft 5 21657601 perft 6 647745807 id 518 -epd r1bqk1rb/pppnpppp/5n2/3p4/2P3PP/2N5/PP1PPP2/R1BQKNRB w GAga - 1 9 +epd r1bqk1rb/pppnpppp/5n2/3p4/2P3PP/2N5/PP1PPP2/R1BQKNRB w GAga - perft 1 32 perft 2 821 perft 3 27121 @@ -4673,7 +4673,7 @@ perft 5 24923473 perft 6 710765657 id 519 -epd rbnqbknr/1p1ppp1p/6p1/p1p5/7P/3P4/PPP1PPP1/RBNQBKNR w HAha - 0 9 +epd rbnqbknr/1p1ppp1p/6p1/p1p5/7P/3P4/PPP1PPP1/RBNQBKNR w HAha - perft 1 24 perft 2 720 perft 3 18842 @@ -4682,7 +4682,7 @@ perft 5 15992882 perft 6 501093456 id 520 -epd r1qbbk1r/pp1ppppp/n1p5/5n2/B1P3P1/8/PP1PPP1P/RNQ1BKNR w HAha - 0 9 +epd r1qbbk1r/pp1ppppp/n1p5/5n2/B1P3P1/8/PP1PPP1P/RNQ1BKNR w HAha - perft 1 27 perft 2 831 perft 3 22293 @@ -4691,7 +4691,7 @@ perft 5 19948650 perft 6 637973209 id 521 -epd rnqkbb1r/p1pppppp/8/8/1p4n1/PP4PP/2PPPP2/RNQKBBNR w HAha - 0 9 +epd rnqkbb1r/p1pppppp/8/8/1p4n1/PP4PP/2PPPP2/RNQKBBNR w HAha - perft 1 18 perft 2 463 perft 3 9519 @@ -4700,7 +4700,7 @@ perft 5 6065231 perft 6 172734380 id 522 -epd rnqk1nrb/pppbpp2/7p/3p2p1/4B3/2N1N1P1/PPPPPP1P/R1QKB1R1 w GAga - 0 9 +epd rnqk1nrb/pppbpp2/7p/3p2p1/4B3/2N1N1P1/PPPPPP1P/R1QKB1R1 w GAga - perft 1 34 perft 2 1171 perft 3 38128 @@ -4709,7 +4709,7 @@ perft 5 42109356 perft 6 1465473753 id 523 -epd rbnqknbr/1pp1ppp1/3p4/7p/p2P2PP/2P5/PP2PP2/RBNQKNBR w HAha - 0 9 +epd rbnqknbr/1pp1ppp1/3p4/7p/p2P2PP/2P5/PP2PP2/RBNQKNBR w HAha - perft 1 32 perft 2 867 perft 3 28342 @@ -4718,7 +4718,7 @@ perft 5 26632459 perft 6 781067145 id 524 -epd rn1bknbr/pq2pppp/1p6/2pp4/P7/1P1P4/2PNPPPP/RNQBK1BR w HAha - 0 9 +epd rn1bknbr/pq2pppp/1p6/2pp4/P7/1P1P4/2PNPPPP/RNQBK1BR w HAha - perft 1 24 perft 2 627 perft 3 16652 @@ -4727,7 +4727,7 @@ perft 5 13200921 perft 6 385193532 id 525 -epd r1qk1bbr/ppp1pp1p/2np1n2/6p1/2PP4/3BP3/PP3PPP/RNQKN1BR w HAha - 2 9 +epd r1qk1bbr/ppp1pp1p/2np1n2/6p1/2PP4/3BP3/PP3PPP/RNQKN1BR w HAha - perft 1 31 perft 2 992 perft 3 30213 @@ -4736,7 +4736,7 @@ perft 5 30397368 perft 6 1011631987 id 526 -epd r1qknrbb/pppp1p2/2n3p1/4p2p/8/QPP5/P1NPPPPP/RN1K1RBB w FAfa - 2 9 +epd r1qknrbb/pppp1p2/2n3p1/4p2p/8/QPP5/P1NPPPPP/RN1K1RBB w FAfa - perft 1 30 perft 2 702 perft 3 21563 @@ -4745,7 +4745,7 @@ perft 5 16813114 perft 6 438096194 id 527 -epd bbkr1qnr/2pppppp/2n5/pp6/8/PPN5/1BPPPPPP/1BR1KQNR w HC - 2 9 +epd bbkr1qnr/2pppppp/2n5/pp6/8/PPN5/1BPPPPPP/1BR1KQNR w HC - perft 1 25 perft 2 573 perft 3 15183 @@ -4754,7 +4754,7 @@ perft 5 10554668 perft 6 283975400 id 528 -epd 1rnbkqnr/1bpppppp/1p6/7P/p2P4/5P2/PPP1P1P1/BRNBKQNR w HBhb - 0 9 +epd 1rnbkqnr/1bpppppp/1p6/7P/p2P4/5P2/PPP1P1P1/BRNBKQNR w HBhb - perft 1 21 perft 2 503 perft 3 11790 @@ -4763,7 +4763,7 @@ perft 5 7679979 perft 6 207799378 id 529 -epd brnkqbnr/2p1pppp/1p6/3p4/1pP5/P6P/3PPPP1/BRNKQBNR w HBhb - 0 9 +epd brnkqbnr/2p1pppp/1p6/3p4/1pP5/P6P/3PPPP1/BRNKQBNR w HBhb - perft 1 28 perft 2 743 perft 3 21054 @@ -4772,7 +4772,7 @@ perft 5 17354516 perft 6 507176753 id 530 -epd br1kqnrb/npp1pppp/8/3p4/p4N2/PP6/2PPPPPP/BR1KQNRB w GBgb - 0 9 +epd br1kqnrb/npp1pppp/8/3p4/p4N2/PP6/2PPPPPP/BR1KQNRB w GBgb - perft 1 31 perft 2 808 perft 3 25585 @@ -4781,7 +4781,7 @@ perft 5 22376575 perft 6 640362920 id 531 -epd rbbnkq1r/pppppp1p/7n/6p1/P5P1/2P2N2/1P1PPP1P/RBBNKQ1R w HAha - 1 9 +epd rbbnkq1r/pppppp1p/7n/6p1/P5P1/2P2N2/1P1PPP1P/RBBNKQ1R w HAha - perft 1 29 perft 2 580 perft 3 17585 @@ -4790,7 +4790,7 @@ perft 5 12730970 perft 6 325226128 id 532 -epd rnbbk1nr/pp2qppp/2ppp3/8/3P4/P1N4N/1PP1PPPP/R1BBKQ1R w HAha - 0 9 +epd rnbbk1nr/pp2qppp/2ppp3/8/3P4/P1N4N/1PP1PPPP/R1BBKQ1R w HAha - perft 1 29 perft 2 838 perft 3 24197 @@ -4799,7 +4799,7 @@ perft 5 21100580 perft 6 646624429 id 533 -epd rnbk1b1r/ppppn1pp/4pp2/7q/7P/P5PB/1PPPPP2/RNBKQ1NR w HAha - 3 9 +epd rnbk1b1r/ppppn1pp/4pp2/7q/7P/P5PB/1PPPPP2/RNBKQ1NR w HAha - perft 1 20 perft 2 729 perft 3 16633 @@ -4808,7 +4808,7 @@ perft 5 14507076 perft 6 498621813 id 534 -epd r2kqnrb/pbppppp1/np5p/8/4Q1P1/3P4/PPP1PP1P/RNBK1NRB w GAga - 2 9 +epd r2kqnrb/pbppppp1/np5p/8/4Q1P1/3P4/PPP1PP1P/RNBK1NRB w GAga - perft 1 47 perft 2 1219 perft 3 55009 @@ -4817,7 +4817,7 @@ perft 5 65239153 perft 6 1834391369 id 535 -epd rbnkbq1r/p1p2ppp/1p2pn2/3p4/P3P3/3P4/1PP1KPPP/RBN1BQNR w ha - 2 9 +epd rbnkbq1r/p1p2ppp/1p2pn2/3p4/P3P3/3P4/1PP1KPPP/RBN1BQNR w ha - perft 1 29 perft 2 923 perft 3 27179 @@ -4826,7 +4826,7 @@ perft 5 26202752 perft 6 868565895 id 536 -epd rk1bb1nr/ppppqppp/n7/1N2p3/6P1/7N/PPPPPP1P/R1KBBQ1R w HA - 6 9 +epd rk1bb1nr/ppppqppp/n7/1N2p3/6P1/7N/PPPPPP1P/R1KBBQ1R w HA - perft 1 27 perft 2 703 perft 3 19478 @@ -4835,7 +4835,7 @@ perft 5 16049807 perft 6 492966455 id 537 -epd rnkqbbnr/p1ppp2p/1p4p1/8/1B3p1P/2NP4/PPP1PPP1/R1KQ1BNR w HAha - 0 9 +epd rnkqbbnr/p1ppp2p/1p4p1/8/1B3p1P/2NP4/PPP1PPP1/R1KQ1BNR w HAha - perft 1 29 perft 2 610 perft 3 18855 @@ -4844,7 +4844,7 @@ perft 5 14020041 perft 6 355083962 id 538 -epd rnkqb1rb/pp1p1ppp/4p3/2P3n1/8/1PP5/P3PPPP/RNKQBNRB w GAga - 0 9 +epd rnkqb1rb/pp1p1ppp/4p3/2P3n1/8/1PP5/P3PPPP/RNKQBNRB w GAga - perft 1 29 perft 2 675 perft 3 20699 @@ -4853,7 +4853,7 @@ perft 5 17000613 perft 6 476598337 id 539 -epd rb1kqnbr/pp1pp1p1/1np2p2/7p/P1P3PP/8/1P1PPP2/RBNKQNBR w HAha - 0 9 +epd rb1kqnbr/pp1pp1p1/1np2p2/7p/P1P3PP/8/1P1PPP2/RBNKQNBR w HAha - perft 1 31 perft 2 1077 perft 3 33661 @@ -4862,7 +4862,7 @@ perft 5 37415304 perft 6 1328374620 id 540 -epd rnkbq1br/ppp2ppp/3p4/Q3p1n1/5P2/3P2P1/PPP1P2P/RNKB1NBR w HAha - 0 9 +epd rnkbq1br/ppp2ppp/3p4/Q3p1n1/5P2/3P2P1/PPP1P2P/RNKB1NBR w HAha - perft 1 41 perft 2 1201 perft 3 46472 @@ -4871,7 +4871,7 @@ perft 5 52991625 perft 6 1675608008 id 541 -epd rn1qnbbr/pp2pppp/2ppk3/8/2PP4/3Q1N2/PP2PPPP/RNK2BBR w HA - 1 9 +epd rn1qnbbr/pp2pppp/2ppk3/8/2PP4/3Q1N2/PP2PPPP/RNK2BBR w HA - perft 1 34 perft 2 666 perft 3 22474 @@ -4880,7 +4880,7 @@ perft 5 15860369 perft 6 353831792 id 542 -epd rnkqnr1b/ppppp1pp/5p2/8/Q1P2P2/8/PP1P2PP/RbK1NRBB w FAfa - 0 9 +epd rnkqnr1b/ppppp1pp/5p2/8/Q1P2P2/8/PP1P2PP/RbK1NRBB w FAfa - perft 1 36 perft 2 876 perft 3 31987 @@ -4889,7 +4889,7 @@ perft 5 29022529 perft 6 736717252 id 543 -epd bbrn1nqr/ppp1k1pp/5p2/3pp3/7P/3PN3/PPP1PPP1/BBRK1NQR w - - 1 9 +epd bbrn1nqr/ppp1k1pp/5p2/3pp3/7P/3PN3/PPP1PPP1/BBRK1NQR w - - perft 1 24 perft 2 583 perft 3 15063 @@ -4898,7 +4898,7 @@ perft 5 10522064 perft 6 280707118 id 544 -epd brnbkn1r/1pppp1p1/4q3/p4p1p/7P/1N3P2/PPPPP1PQ/BR1BKN1R w HBhb - 2 9 +epd brnbkn1r/1pppp1p1/4q3/p4p1p/7P/1N3P2/PPPPP1PQ/BR1BKN1R w HBhb - perft 1 27 perft 2 935 perft 3 26120 @@ -4907,7 +4907,7 @@ perft 5 26000648 perft 6 873063158 id 545 -epd br1knbqr/pp2p1pp/1n6/2pp1p2/6P1/2P4B/PP1PPPQP/BRNKN2R w HBhb - 0 9 +epd br1knbqr/pp2p1pp/1n6/2pp1p2/6P1/2P4B/PP1PPPQP/BRNKN2R w HBhb - perft 1 27 perft 2 681 perft 3 19202 @@ -4916,7 +4916,7 @@ perft 5 14954779 perft 6 415624943 id 546 -epd brnk1qrb/p1ppppp1/1p5p/8/P3n3/1N4P1/1PPPPPRP/BR1KNQ1B w Bgb - 0 9 +epd brnk1qrb/p1ppppp1/1p5p/8/P3n3/1N4P1/1PPPPPRP/BR1KNQ1B w Bgb - perft 1 22 perft 2 638 perft 3 13991 @@ -4925,7 +4925,7 @@ perft 5 9760752 perft 6 293499724 id 547 -epd rbbnknqr/pppp3p/5pp1/8/1P1pP3/7P/P1P2PP1/RBBNKNQR w HAha - 0 9 +epd rbbnknqr/pppp3p/5pp1/8/1P1pP3/7P/P1P2PP1/RBBNKNQR w HAha - perft 1 29 perft 2 756 perft 3 21616 @@ -4934,7 +4934,7 @@ perft 5 17602252 perft 6 528140595 id 548 -epd 1nbbknqr/rpp1ppp1/1Q1p3p/p7/2P2PP1/8/PP1PP2P/RNBBKN1R w HAh - 2 9 +epd 1nbbknqr/rpp1ppp1/1Q1p3p/p7/2P2PP1/8/PP1PP2P/RNBBKN1R w HAh - perft 1 37 perft 2 977 perft 3 34977 @@ -4943,7 +4943,7 @@ perft 5 33695089 perft 6 940198007 id 549 -epd rnb2bqr/ppkpppp1/3n3p/2p5/6PP/2N2P2/PPPPP3/R1BKNBQR w HA - 2 9 +epd rnb2bqr/ppkpppp1/3n3p/2p5/6PP/2N2P2/PPPPP3/R1BKNBQR w HA - perft 1 30 perft 2 647 perft 3 20365 @@ -4952,7 +4952,7 @@ perft 5 15115531 perft 6 369257622 id 550 -epd rn1k1qrb/p1pppppp/bp6/8/4n3/P4BPP/1PPPPP2/RNBKNQR1 w GAga - 2 9 +epd rn1k1qrb/p1pppppp/bp6/8/4n3/P4BPP/1PPPPP2/RNBKNQR1 w GAga - perft 1 22 perft 2 670 perft 3 14998 @@ -4961,7 +4961,7 @@ perft 5 11199653 perft 6 339919682 id 551 -epd rb2bnqr/nppkpppp/3p4/p7/1P6/P2N2P1/2PPPP1P/RB1KBNQR w HA - 3 9 +epd rb2bnqr/nppkpppp/3p4/p7/1P6/P2N2P1/2PPPP1P/RB1KBNQR w HA - perft 1 22 perft 2 479 perft 3 11475 @@ -4970,7 +4970,7 @@ perft 5 6831555 perft 6 167329117 id 552 -epd r1kbb1qr/2pppppp/np2n3/p7/2P3P1/8/PP1PPPQP/RNKBBN1R w HAha - 1 9 +epd r1kbb1qr/2pppppp/np2n3/p7/2P3P1/8/PP1PPPQP/RNKBBN1R w HAha - perft 1 32 perft 2 723 perft 3 23953 @@ -4979,7 +4979,7 @@ perft 5 19472074 perft 6 504622114 id 553 -epd rnknbb1r/p1ppp1pp/8/1p1P1p1q/8/P1P5/1P2PPPP/RNKNBBQR w HAha - 1 9 +epd rnknbb1r/p1ppp1pp/8/1p1P1p1q/8/P1P5/1P2PPPP/RNKNBBQR w HAha - perft 1 19 perft 2 607 perft 3 12733 @@ -4988,7 +4988,7 @@ perft 5 9753617 perft 6 325177085 id 554 -epd rnkn1qrb/pp1bp1pp/2p5/1N1p1p2/8/2P5/PPKPPPPP/R2NBQRB w ga - 2 9 +epd rnkn1qrb/pp1bp1pp/2p5/1N1p1p2/8/2P5/PPKPPPPP/R2NBQRB w ga - perft 1 27 perft 2 533 perft 3 14549 @@ -4997,7 +4997,7 @@ perft 5 9206957 perft 6 232664675 id 555 -epd r1nknqbr/pp2p1pp/2p2p2/3p4/6P1/PP1P4/2P1PP1b/RBNKNQBR w HAha - 0 9 +epd r1nknqbr/pp2p1pp/2p2p2/3p4/6P1/PP1P4/2P1PP1b/RBNKNQBR w HAha - perft 1 20 perft 2 582 perft 3 13777 @@ -5006,7 +5006,7 @@ perft 5 10708639 perft 6 326565393 id 556 -epd rnkb1qbr/p1pp1p1p/1p2pn2/1Q4p1/4P3/N4P2/PPPP2PP/R1KBN1BR w HAha - 0 9 +epd rnkb1qbr/p1pp1p1p/1p2pn2/1Q4p1/4P3/N4P2/PPPP2PP/R1KBN1BR w HAha - perft 1 40 perft 2 1038 perft 3 39356 @@ -5015,7 +5015,7 @@ perft 5 39145902 perft 6 1079612614 id 557 -epd rn2qbbr/1pkppp1p/p3n1p1/8/8/2P2P2/PP1PP1PP/RNKN1BBR w HA - 0 9 +epd rn2qbbr/1pkppp1p/p3n1p1/8/8/2P2P2/PP1PP1PP/RNKN1BBR w HA - perft 1 24 perft 2 605 perft 3 14888 @@ -5024,7 +5024,7 @@ perft 5 9687507 perft 6 260874068 id 558 -epd rn1nqrbb/p1kppp1p/8/1pp3p1/1P6/2N1P3/P1PP1PPP/RK1NQRBB w - - 0 9 +epd rn1nqrbb/p1kppp1p/8/1pp3p1/1P6/2N1P3/P1PP1PPP/RK1NQRBB w - - perft 1 21 perft 2 540 perft 3 12489 @@ -5033,7 +5033,7 @@ perft 5 8436136 perft 6 237525904 id 559 -epd bbrnknrq/1pp3pp/p2p1p2/4p3/P7/1P2N3/2PPPPPP/BBRN1RKQ w gc - 0 9 +epd bbrnknrq/1pp3pp/p2p1p2/4p3/P7/1P2N3/2PPPPPP/BBRN1RKQ w gc - perft 1 24 perft 2 527 perft 3 13900 @@ -5042,7 +5042,7 @@ perft 5 9139962 perft 6 226253685 id 560 -epd brnb1nrq/pppp1kpp/4p3/8/5p1P/P1P3P1/1P1PPP2/BRNBKNRQ w GB - 1 9 +epd brnb1nrq/pppp1kpp/4p3/8/5p1P/P1P3P1/1P1PPP2/BRNBKNRQ w GB - perft 1 29 perft 2 773 perft 3 23904 @@ -5051,7 +5051,7 @@ perft 5 20503775 perft 6 560338709 id 561 -epd br1k1brq/ppppp2p/1n1n1pp1/8/P1P5/3P2P1/1P2PP1P/BRNKNBRQ w GBgb - 0 9 +epd br1k1brq/ppppp2p/1n1n1pp1/8/P1P5/3P2P1/1P2PP1P/BRNKNBRQ w GBgb - perft 1 28 perft 2 811 perft 3 23550 @@ -5060,7 +5060,7 @@ perft 5 19913758 perft 6 565143976 id 562 -epd 1r1knrqb/n1pppppp/p1b5/1p6/8/3N1P2/PPPPP1PP/BRNK1RQB w fb - 3 9 +epd 1r1knrqb/n1pppppp/p1b5/1p6/8/3N1P2/PPPPP1PP/BRNK1RQB w fb - perft 1 29 perft 2 753 perft 3 23210 @@ -5069,7 +5069,7 @@ perft 5 20044474 perft 6 558383603 id 563 -epd rbbnk1rq/pppppppp/8/3Pn3/8/4P1P1/PPP2P1P/RBBNKNRQ w GAga - 1 9 +epd rbbnk1rq/pppppppp/8/3Pn3/8/4P1P1/PPP2P1P/RBBNKNRQ w GAga - perft 1 22 perft 2 551 perft 3 12619 @@ -5078,7 +5078,7 @@ perft 5 8204171 perft 6 217689974 id 564 -epd rnbbk1rq/2pppp1p/p3n1p1/1p6/P3N3/8/1PPPPPPP/RNBB1KRQ w ga - 0 9 +epd rnbbk1rq/2pppp1p/p3n1p1/1p6/P3N3/8/1PPPPPPP/RNBB1KRQ w ga - perft 1 26 perft 2 742 perft 3 20061 @@ -5087,7 +5087,7 @@ perft 5 16787080 perft 6 525678162 id 565 -epd rnbkn1rq/ppppppb1/6p1/7p/2B2P2/1P2P3/P1PP2PP/RNBKN1RQ w GAga - 1 9 +epd rnbkn1rq/ppppppb1/6p1/7p/2B2P2/1P2P3/P1PP2PP/RNBKN1RQ w GAga - perft 1 28 perft 2 799 perft 3 23210 @@ -5096,7 +5096,7 @@ perft 5 20755098 perft 6 639632905 id 566 -epd rn1knrqb/p2pppp1/b1p5/1p5p/2P2P2/1P6/P2PP1PP/RNBKNRQB w FAfa - 1 9 +epd rn1knrqb/p2pppp1/b1p5/1p5p/2P2P2/1P6/P2PP1PP/RNBKNRQB w FAfa - perft 1 30 perft 2 579 perft 3 18481 @@ -5105,7 +5105,7 @@ perft 5 13257198 perft 6 311282465 id 567 -epd rbnkbnrq/pp2p1Np/2p2p2/8/3p4/8/PPPPPPPP/RBNKBR1Q w Aga - 0 9 +epd rbnkbnrq/pp2p1Np/2p2p2/8/3p4/8/PPPPPPPP/RBNKBR1Q w Aga - perft 1 23 perft 2 670 perft 3 16435 @@ -5114,7 +5114,7 @@ perft 5 13012378 perft 6 411860744 id 568 -epd rk1bbnrq/ppp1pppp/n7/3p4/5P2/3P2NP/PPP1P1P1/RNKBB1RQ w GA - 0 9 +epd rk1bbnrq/ppp1pppp/n7/3p4/5P2/3P2NP/PPP1P1P1/RNKBB1RQ w GA - perft 1 26 perft 2 597 perft 3 16238 @@ -5123,7 +5123,7 @@ perft 5 11269462 perft 6 296701249 id 569 -epd r1knbbrq/pppp2p1/2n1p2p/5p2/4P3/P1PP4/1P3PPP/RNKNBBRQ w GAga - 1 9 +epd r1knbbrq/pppp2p1/2n1p2p/5p2/4P3/P1PP4/1P3PPP/RNKNBBRQ w GAga - perft 1 20 perft 2 596 perft 3 13091 @@ -5132,7 +5132,7 @@ perft 5 9416862 perft 6 293659781 id 570 -epd rnknbrqb/p1p1pp1p/3p4/1p1N2p1/8/N7/PPPPPPPP/1RK1BRQB w Ffa - 0 9 +epd rnknbrqb/p1p1pp1p/3p4/1p1N2p1/8/N7/PPPPPPPP/1RK1BRQB w Ffa - perft 1 26 perft 2 724 perft 3 18942 @@ -5141,7 +5141,7 @@ perft 5 15257204 perft 6 461293885 id 571 -epd rbnknrb1/1p1ppp1p/p1p3p1/8/1P3P2/1R6/PqPPP1PP/RBNKN1BQ w Afa - 0 9 +epd rbnknrb1/1p1ppp1p/p1p3p1/8/1P3P2/1R6/PqPPP1PP/RBNKN1BQ w Afa - perft 1 31 perft 2 1183 perft 3 34723 @@ -5150,7 +5150,7 @@ perft 5 38722152 perft 6 1421492227 id 572 -epd rnkbnrbq/2p1ppp1/p7/1p1p3p/3P4/1P4P1/P1P1PP1P/RNKBNRBQ w FAfa - 0 9 +epd rnkbnrbq/2p1ppp1/p7/1p1p3p/3P4/1P4P1/P1P1PP1P/RNKBNRBQ w FAfa - perft 1 24 perft 2 506 perft 3 12748 @@ -5159,7 +5159,7 @@ perft 5 8086100 perft 6 207129256 id 573 -epd r1knrbbq/pp1ppppp/2p1n3/8/2P3P1/P7/1PKPPP1P/RN1NRBBQ w ea - 0 9 +epd r1knrbbq/pp1ppppp/2p1n3/8/2P3P1/P7/1PKPPP1P/RN1NRBBQ w ea - perft 1 28 perft 2 570 perft 3 16037 @@ -5168,7 +5168,7 @@ perft 5 10278695 perft 6 242592363 id 574 -epd rnknrq1b/ppp1p1p1/4b3/3p1p1p/6P1/P4P2/1PPPPQ1P/RNKNR1BB w EAea - 2 9 +epd rnknrq1b/ppp1p1p1/4b3/3p1p1p/6P1/P4P2/1PPPPQ1P/RNKNR1BB w EAea - perft 1 30 perft 2 739 perft 3 23124 @@ -5177,7 +5177,7 @@ perft 5 19252739 perft 6 521629794 id 575 -epd bbqr1krn/pppp1p1p/5n2/4p1p1/3P4/P3QP2/1PP1P1PP/BB1RNKRN w GDgd - 0 9 +epd bbqr1krn/pppp1p1p/5n2/4p1p1/3P4/P3QP2/1PP1P1PP/BB1RNKRN w GDgd - perft 1 31 perft 2 799 perft 3 25627 @@ -5186,7 +5186,7 @@ perft 5 22172123 perft 6 609277274 id 576 -epd bq1b1krn/pp1ppppp/3n4/2r5/3p3N/6N1/PPP1PPPP/BQRB1KR1 w GCg - 2 9 +epd bq1b1krn/pp1ppppp/3n4/2r5/3p3N/6N1/PPP1PPPP/BQRB1KR1 w GCg - perft 1 21 perft 2 798 perft 3 18571 @@ -5195,7 +5195,7 @@ perft 5 17546069 perft 6 647165916 id 577 -epd bqrnkbrn/2pp1pp1/p7/1p2p2p/1P6/4N3/P1PPPPPP/BQR1KBRN w GCgc - 0 9 +epd bqrnkbrn/2pp1pp1/p7/1p2p2p/1P6/4N3/P1PPPPPP/BQR1KBRN w GCgc - perft 1 27 perft 2 783 perft 3 22327 @@ -5204,7 +5204,7 @@ perft 5 20059741 perft 6 624462073 id 578 -epd bqr1krnb/1np1pppp/8/pp1p4/8/2P2N2/PP1PPPPP/BQRNKR1B w FCfc - 0 9 +epd bqr1krnb/1np1pppp/8/pp1p4/8/2P2N2/PP1PPPPP/BQRNKR1B w FCfc - perft 1 28 perft 2 636 perft 3 18874 @@ -5213,7 +5213,7 @@ perft 5 14237097 perft 6 372181570 id 579 -epd qbb1rkrn/1ppppppp/p7/7n/8/P2P4/1PP1PPPP/QBBRNKRN w Gg - 0 9 +epd qbb1rkrn/1ppppppp/p7/7n/8/P2P4/1PP1PPPP/QBBRNKRN w Gg - perft 1 25 perft 2 547 perft 3 13837 @@ -5222,7 +5222,7 @@ perft 5 8849383 perft 6 229112926 id 580 -epd 1rbbnkrn/p1p1pp1p/2q5/1p1p2p1/8/2P3P1/PP1PPP1P/QRBBNKRN w GBgb - 2 9 +epd 1rbbnkrn/p1p1pp1p/2q5/1p1p2p1/8/2P3P1/PP1PPP1P/QRBBNKRN w GBgb - perft 1 24 perft 2 1010 perft 3 24370 @@ -5231,7 +5231,7 @@ perft 5 24328258 perft 6 961371180 id 581 -epd qrb1kbrn/ppp1p2p/4npp1/3p4/8/1PP4P/PR1PPPP1/Q1BNKBRN w Ggb - 1 9 +epd qrb1kbrn/ppp1p2p/4npp1/3p4/8/1PP4P/PR1PPPP1/Q1BNKBRN w Ggb - perft 1 18 perft 2 451 perft 3 9291 @@ -5240,7 +5240,7 @@ perft 5 5568106 perft 6 155744022 id 582 -epd qr2krnb/p1p1pppp/b1np4/1p6/3NP3/7P/PPPP1PP1/QRBNKR1B w FBfb - 2 9 +epd qr2krnb/p1p1pppp/b1np4/1p6/3NP3/7P/PPPP1PP1/QRBNKR1B w FBfb - perft 1 25 perft 2 667 perft 3 17081 @@ -5249,7 +5249,7 @@ perft 5 12458875 perft 6 361495148 id 583 -epd qbrnbkrn/ppp3pp/3p4/5p2/2P1pP2/6PP/PP1PP3/QBRNBKRN w GCgc - 0 9 +epd qbrnbkrn/ppp3pp/3p4/5p2/2P1pP2/6PP/PP1PP3/QBRNBKRN w GCgc - perft 1 24 perft 2 650 perft 3 16835 @@ -5258,7 +5258,7 @@ perft 5 12187382 perft 6 326834539 id 584 -epd qrnb1krn/ppp1p1pp/5p2/2Np4/b2P4/2P5/PP2PPPP/QR1BBKRN w GBgb - 0 9 +epd qrnb1krn/ppp1p1pp/5p2/2Np4/b2P4/2P5/PP2PPPP/QR1BBKRN w GBgb - perft 1 27 perft 2 641 perft 3 17490 @@ -5267,7 +5267,7 @@ perft 5 12103076 perft 6 310695797 id 585 -epd qrnkbbrn/pp2pp2/8/2pp2pp/6PP/3P4/PPPKPP2/QRN1BBRN w gb - 0 9 +epd qrnkbbrn/pp2pp2/8/2pp2pp/6PP/3P4/PPPKPP2/QRN1BBRN w gb - perft 1 22 perft 2 554 perft 3 13116 @@ -5276,7 +5276,7 @@ perft 5 9014737 perft 6 258925091 id 586 -epd qrnkbrnb/p1p1ppp1/1p6/3p4/3P3p/5N1P/PPP1PPP1/QRNKBR1B w FBfb - 0 9 +epd qrnkbrnb/p1p1ppp1/1p6/3p4/3P3p/5N1P/PPP1PPP1/QRNKBR1B w FBfb - perft 1 24 perft 2 529 perft 3 13205 @@ -5285,7 +5285,7 @@ perft 5 8295874 perft 6 213856651 id 587 -epd qbr1krbn/1pppp1pp/p7/5pn1/2PP4/8/PPB1PPPP/Q1RNKRBN w FCfc - 0 9 +epd qbr1krbn/1pppp1pp/p7/5pn1/2PP4/8/PPB1PPPP/Q1RNKRBN w FCfc - perft 1 26 perft 2 831 perft 3 21651 @@ -5294,7 +5294,7 @@ perft 5 18961456 perft 6 621884383 id 588 -epd 1rnbkrbn/1qp1pppp/3p4/pp6/4P3/1NP4P/PP1P1PP1/QR1BKRBN w FBfb - 0 9 +epd 1rnbkrbn/1qp1pppp/3p4/pp6/4P3/1NP4P/PP1P1PP1/QR1BKRBN w FBfb - perft 1 24 perft 2 597 perft 3 15089 @@ -5303,7 +5303,7 @@ perft 5 10832084 perft 6 307793179 id 589 -epd q1rkrbbn/ppp1pppp/8/3p4/1PnP4/P7/1RP1PPPP/Q1NKRBBN w Ee - 1 9 +epd q1rkrbbn/ppp1pppp/8/3p4/1PnP4/P7/1RP1PPPP/Q1NKRBBN w Ee - perft 1 20 perft 2 520 perft 3 10769 @@ -5312,7 +5312,7 @@ perft 5 6452205 perft 6 170268300 id 590 -epd qrnkrn1b/ppppp1pp/4b3/7P/6p1/P7/1PPPPP2/QRNKRNBB w EBeb - 0 9 +epd qrnkrn1b/ppppp1pp/4b3/7P/6p1/P7/1PPPPP2/QRNKRNBB w EBeb - perft 1 26 perft 2 566 perft 3 15623 @@ -5321,7 +5321,7 @@ perft 5 10940750 perft 6 287987207 id 591 -epd bbr1nkrn/ppp1pppp/3q4/3p4/8/P7/1PPPPPPP/BBRQNRKN w gc - 5 9 +epd bbr1nkrn/ppp1pppp/3q4/3p4/8/P7/1PPPPPPP/BBRQNRKN w gc - perft 1 19 perft 2 661 perft 3 13895 @@ -5330,7 +5330,7 @@ perft 5 10870247 perft 6 356399665 id 592 -epd brqbnkrn/pp1pp2p/5pp1/2p5/4P3/P2P1N2/1PP2PPP/BRQB1KRN w GBgb - 0 9 +epd brqbnkrn/pp1pp2p/5pp1/2p5/4P3/P2P1N2/1PP2PPP/BRQB1KRN w GBgb - perft 1 27 perft 2 679 perft 3 19916 @@ -5339,7 +5339,7 @@ perft 5 16391730 perft 6 455940859 id 593 -epd 2qnkbrn/p1pppppp/8/1r6/1p2bP2/7N/PPPPP1PP/BR1QKBRN w GBg - 4 9 +epd 2qnkbrn/p1pppppp/8/1r6/1p2bP2/7N/PPPPP1PP/BR1QKBRN w GBg - perft 1 18 perft 2 774 perft 3 15713 @@ -5348,7 +5348,7 @@ perft 5 14371755 perft 6 559579332 id 594 -epd r1qnkr1b/p1pppppp/7n/1p6/8/1P3b1N/PRPPPPPP/B1QNK1RB w f - 5 9 +epd r1qnkr1b/p1pppppp/7n/1p6/8/1P3b1N/PRPPPPPP/B1QNK1RB w f - perft 1 21 perft 2 677 perft 3 15437 @@ -5357,7 +5357,7 @@ perft 5 12463801 perft 6 410795298 id 595 -epd rbbqn1rn/pppp1pp1/3k4/4p2Q/2PPP3/8/PP3PPP/RBB1NKRN w GA - 1 9 +epd rbbqn1rn/pppp1pp1/3k4/4p2Q/2PPP3/8/PP3PPP/RBB1NKRN w GA - perft 1 40 perft 2 742 perft 3 28757 @@ -5366,7 +5366,7 @@ perft 5 21852196 perft 6 471452088 id 596 -epd rqbbnkrn/3pppp1/p1p4p/1p6/5P2/P2N4/1PPPP1PP/RQBBK1RN w ga - 0 9 +epd rqbbnkrn/3pppp1/p1p4p/1p6/5P2/P2N4/1PPPP1PP/RQBBK1RN w ga - perft 1 23 perft 2 665 perft 3 16400 @@ -5375,7 +5375,7 @@ perft 5 12794736 perft 6 396640086 id 597 -epd r2nkbrn/pp2pppp/8/2ppqb2/2P3P1/5P2/PP1PPN1P/RQB1KBRN w GAga - 3 9 +epd r2nkbrn/pp2pppp/8/2ppqb2/2P3P1/5P2/PP1PPN1P/RQB1KBRN w GAga - perft 1 28 perft 2 1108 perft 3 31164 @@ -5384,7 +5384,7 @@ perft 5 34780853 perft 6 1292405738 id 598 -epd rqbnk1nb/p1pppr1p/5p2/1p4p1/1PP1P3/8/P2P1PPP/RQBNKRNB w FAa - 1 9 +epd rqbnk1nb/p1pppr1p/5p2/1p4p1/1PP1P3/8/P2P1PPP/RQBNKRNB w FAa - perft 1 26 perft 2 650 perft 3 18208 @@ -5393,7 +5393,7 @@ perft 5 14565370 perft 6 416833400 id 599 -epd rbqnb1rn/p1pp1kpp/1p2pp2/8/4P2P/P5P1/1PPP1P2/RBQNBKRN w GA - 0 9 +epd rbqnb1rn/p1pp1kpp/1p2pp2/8/4P2P/P5P1/1PPP1P2/RBQNBKRN w GA - perft 1 20 perft 2 437 perft 3 9423 @@ -5402,7 +5402,7 @@ perft 5 5282124 perft 6 132309824 id 600 -epd rqnbbkrn/p1p1pppp/3p4/1p5B/8/1P1NP3/P1PP1PPP/RQ2BKRN w GAga - 0 9 +epd rqnbbkrn/p1p1pppp/3p4/1p5B/8/1P1NP3/P1PP1PPP/RQ2BKRN w GAga - perft 1 30 perft 2 606 perft 3 18382 @@ -5411,7 +5411,7 @@ perft 5 12989786 perft 6 326601372 id 601 -epd rqnkbbr1/ppppp1pp/5p2/7n/8/2PNP2P/PP1P1PP1/RQ1KBBRN w GAga - 1 9 +epd rqnkbbr1/ppppp1pp/5p2/7n/8/2PNP2P/PP1P1PP1/RQ1KBBRN w GAga - perft 1 23 perft 2 482 perft 3 12506 @@ -5420,7 +5420,7 @@ perft 5 8430874 perft 6 217797292 id 602 -epd r1nkbrnb/2ppppp1/1q6/pp5p/1P6/P3P3/2PPKPPP/RQN1BRNB w fa - 2 9 +epd r1nkbrnb/2ppppp1/1q6/pp5p/1P6/P3P3/2PPKPPP/RQN1BRNB w fa - perft 1 25 perft 2 827 perft 3 21518 @@ -5429,7 +5429,7 @@ perft 5 19290675 perft 6 632892337 id 603 -epd rbqnkrbn/p1ppppp1/7p/1p6/7P/2N1P3/PPPP1PPB/RBQ1KR1N w FAfa - 1 9 +epd rbqnkrbn/p1ppppp1/7p/1p6/7P/2N1P3/PPPP1PPB/RBQ1KR1N w FAfa - perft 1 30 perft 2 627 perft 3 18566 @@ -5438,7 +5438,7 @@ perft 5 12976682 perft 6 337377291 id 604 -epd r1nbkrbn/p1qp1ppp/8/1pp1p3/2P1P3/6P1/PP1PBP1P/RQN1KRBN w FAfa - 2 9 +epd r1nbkrbn/p1qp1ppp/8/1pp1p3/2P1P3/6P1/PP1PBP1P/RQN1KRBN w FAfa - perft 1 22 perft 2 616 perft 3 14503 @@ -5447,7 +5447,7 @@ perft 5 10850952 perft 6 335943324 id 605 -epd rqnkr1bn/ppp1ppb1/3p2pp/8/P7/2P2P2/1PKPP1PP/RQN1RBBN w ea - 1 9 +epd rqnkr1bn/ppp1ppb1/3p2pp/8/P7/2P2P2/1PKPP1PP/RQN1RBBN w ea - perft 1 31 perft 2 679 perft 3 21365 @@ -5456,7 +5456,7 @@ perft 5 15661072 perft 6 379844460 id 606 -epd r2krnbb/qppp1ppp/1n6/p3p3/PP6/4N3/N1PPPPPP/RQ1KR1BB w EAea - 4 9 +epd r2krnbb/qppp1ppp/1n6/p3p3/PP6/4N3/N1PPPPPP/RQ1KR1BB w EAea - perft 1 24 perft 2 645 perft 3 17054 @@ -5465,7 +5465,7 @@ perft 5 13837270 perft 6 416239106 id 607 -epd bbr1qk1n/1ppppp1p/2n5/p7/P7/1P2P3/2PP1PrP/1BRNQKRN w GCc - 0 9 +epd bbr1qk1n/1ppppp1p/2n5/p7/P7/1P2P3/2PP1PrP/1BRNQKRN w GCc - perft 1 18 perft 2 520 perft 3 10680 @@ -5474,7 +5474,7 @@ perft 5 7215306 perft 6 207612575 id 608 -epd brnbq1rn/2ppppkp/p5p1/1p6/8/1BP3P1/PP1PPP1P/BRN1QRKN w - - 0 9 +epd brnbq1rn/2ppppkp/p5p1/1p6/8/1BP3P1/PP1PPP1P/BRN1QRKN w - - perft 1 21 perft 2 625 perft 3 13989 @@ -5483,7 +5483,7 @@ perft 5 9929336 perft 6 300902534 id 609 -epd brn1kbrn/pp2p1pp/3p4/q1p2p2/2P4P/6P1/PP1PPP2/BRNQKBRN w GBgb - 1 9 +epd brn1kbrn/pp2p1pp/3p4/q1p2p2/2P4P/6P1/PP1PPP2/BRNQKBRN w GBgb - perft 1 18 perft 2 477 perft 3 10205 @@ -5492,7 +5492,7 @@ perft 5 6720181 perft 6 187205941 id 610 -epd brn1krnb/p3pppp/1qpp4/1p6/2P3P1/1P6/P2PPP1P/BRNQKRNB w FBfb - 1 9 +epd brn1krnb/p3pppp/1qpp4/1p6/2P3P1/1P6/P2PPP1P/BRNQKRNB w FBfb - perft 1 30 perft 2 835 perft 3 24761 @@ -5501,7 +5501,7 @@ perft 5 21806428 perft 6 654487872 id 611 -epd r1b1qkrn/1p1ppppp/p1p1n3/8/4P3/1PN5/P1PPQPPb/RBB2KRN w GAga - 0 9 +epd r1b1qkrn/1p1ppppp/p1p1n3/8/4P3/1PN5/P1PPQPPb/RBB2KRN w GAga - perft 1 28 perft 2 825 perft 3 24536 @@ -5510,7 +5510,7 @@ perft 5 22079005 perft 6 647939781 id 612 -epd r1bbqk1n/p1pppprp/n7/1p4p1/5P2/2N3N1/PPPPP1PP/1RBBQKR1 w Ga - 4 9 +epd r1bbqk1n/p1pppprp/n7/1p4p1/5P2/2N3N1/PPPPP1PP/1RBBQKR1 w Ga - perft 1 25 perft 2 545 perft 3 14657 @@ -5519,7 +5519,7 @@ perft 5 10271111 perft 6 273864588 id 613 -epd rnbqkbrn/p1pp1pp1/4p3/7p/2p4P/2P5/PP1PPPP1/R1BQKBRN w GAga - 0 9 +epd rnbqkbrn/p1pp1pp1/4p3/7p/2p4P/2P5/PP1PPPP1/R1BQKBRN w GAga - perft 1 17 perft 2 445 perft 3 9076 @@ -5528,7 +5528,7 @@ perft 5 5918310 perft 6 174733195 id 614 -epd rnbqkrnb/1p1pp1p1/2p4p/p4p2/3P2P1/7N/PPPBPP1P/RN1QKR1B w FAfa - 0 9 +epd rnbqkrnb/1p1pp1p1/2p4p/p4p2/3P2P1/7N/PPPBPP1P/RN1QKR1B w FAfa - perft 1 34 perft 2 746 perft 3 25319 @@ -5537,7 +5537,7 @@ perft 5 21285553 perft 6 569141201 id 615 -epd rbnqbkr1/1ppppp2/p5n1/6pp/4P3/1N6/PPPP1PPP/RBQ1BRKN w ga - 2 9 +epd rbnqbkr1/1ppppp2/p5n1/6pp/4P3/1N6/PPPP1PPP/RBQ1BRKN w ga - perft 1 18 perft 2 466 perft 3 9683 @@ -5546,7 +5546,7 @@ perft 5 6051500 perft 6 170135726 id 616 -epd rnqb1krn/ppppp1p1/7p/7b/P1P2pPP/8/1P1PPP2/RNQBBKRN w GAga - 0 9 +epd rnqb1krn/ppppp1p1/7p/7b/P1P2pPP/8/1P1PPP2/RNQBBKRN w GAga - perft 1 24 perft 2 575 perft 3 15400 @@ -5555,7 +5555,7 @@ perft 5 11039042 perft 6 291243811 id 617 -epd rnqkbbr1/p1pp1ppp/4p3/1p6/P3P2n/5P2/1PPP1NPP/RNQKBBR1 w GAga - 2 9 +epd rnqkbbr1/p1pp1ppp/4p3/1p6/P3P2n/5P2/1PPP1NPP/RNQKBBR1 w GAga - perft 1 27 perft 2 803 perft 3 22883 @@ -5564,7 +5564,7 @@ perft 5 20666099 perft 6 638696065 id 618 -epd rn1kbrnb/1qppp1pp/1p6/p4p2/1B1P4/1P5N/P1P1PPPP/RNQK1R1B w FAfa - 0 9 +epd rn1kbrnb/1qppp1pp/1p6/p4p2/1B1P4/1P5N/P1P1PPPP/RNQK1R1B w FAfa - perft 1 37 perft 2 1209 perft 3 43015 @@ -5573,7 +5573,7 @@ perft 5 49748034 perft 6 1671593862 id 619 -epd rbnqkrbn/Bppp1p2/p5pp/4p3/5P2/6PP/PPPPP3/RBNQKR1N w FAfa - 0 9 +epd rbnqkrbn/Bppp1p2/p5pp/4p3/5P2/6PP/PPPPP3/RBNQKR1N w FAfa - perft 1 29 perft 2 720 perft 3 20434 @@ -5582,7 +5582,7 @@ perft 5 15384362 perft 6 421343249 id 620 -epd rnqbkr1n/1p1ppbpp/3p1p2/p7/8/1P6/P1PPPPPP/R1QBKRBN w FAfa - 0 9 +epd rnqbkr1n/1p1ppbpp/3p1p2/p7/8/1P6/P1PPPPPP/R1QBKRBN w FAfa - perft 1 20 perft 2 657 perft 3 14424 @@ -5591,7 +5591,7 @@ perft 5 11843134 perft 6 413965054 id 621 -epd rnqkrb1n/ppppp3/6p1/5p1p/2b2P2/P1N5/1PPPP1PP/RQ1KRBBN w EAea - 1 9 +epd rnqkrb1n/ppppp3/6p1/5p1p/2b2P2/P1N5/1PPPP1PP/RQ1KRBBN w EAea - perft 1 28 perft 2 749 perft 3 20684 @@ -5600,7 +5600,7 @@ perft 5 15379233 perft 6 417191461 id 622 -epd rnqk1nbb/1pp2ppp/3pr3/p3p3/3P1P2/2N3N1/PPP1P1PP/R1QKR1BB w EAa - 1 9 +epd rnqk1nbb/1pp2ppp/3pr3/p3p3/3P1P2/2N3N1/PPP1P1PP/R1QKR1BB w EAa - perft 1 29 perft 2 883 perft 3 26412 @@ -5609,7 +5609,7 @@ perft 5 25144295 perft 6 789705382 id 623 -epd bbr1kqrn/p1p1ppp1/1p2n2p/3p4/1P1P4/2N5/P1P1PPPP/BBR1KQRN w GCgc - 0 9 +epd bbr1kqrn/p1p1ppp1/1p2n2p/3p4/1P1P4/2N5/P1P1PPPP/BBR1KQRN w GCgc - perft 1 22 perft 2 485 perft 3 11475 @@ -5618,7 +5618,7 @@ perft 5 6825123 perft 6 171793012 id 624 -epd brnbkq1n/ppp1ppr1/7p/3p2p1/2P3PP/8/PPBPPP2/BRN1KQRN w GBb - 2 9 +epd brnbkq1n/ppp1ppr1/7p/3p2p1/2P3PP/8/PPBPPP2/BRN1KQRN w GBb - perft 1 30 perft 2 634 perft 3 19017 @@ -5627,7 +5627,7 @@ perft 5 13674310 perft 6 345386924 id 625 -epd brnkqbr1/1pppp1pp/5p2/p7/P1P1P2n/8/1P1P1PP1/BRNKQBRN w GBgb - 0 9 +epd brnkqbr1/1pppp1pp/5p2/p7/P1P1P2n/8/1P1P1PP1/BRNKQBRN w GBgb - perft 1 21 perft 2 504 perft 3 11672 @@ -5636,7 +5636,7 @@ perft 5 7778289 perft 6 217596497 id 626 -epd b1rkqrnb/p1ppp1pp/1p1n4/5p2/5P2/PN5P/1PPPP1P1/BR1KQRNB w FBf - 0 9 +epd b1rkqrnb/p1ppp1pp/1p1n4/5p2/5P2/PN5P/1PPPP1P1/BR1KQRNB w FBf - perft 1 23 perft 2 688 perft 3 17259 @@ -5645,7 +5645,7 @@ perft 5 14228372 perft 6 451842354 id 627 -epd 1bbnkqrn/rppppp2/p5p1/7p/7P/P1P1P3/1P1P1PP1/RBBNKQRN w GAg - 1 9 +epd 1bbnkqrn/rppppp2/p5p1/7p/7P/P1P1P3/1P1P1PP1/RBBNKQRN w GAg - perft 1 25 perft 2 450 perft 3 12391 @@ -5654,7 +5654,7 @@ perft 5 7752404 perft 6 185393913 id 628 -epd rnbbkqr1/1pppppp1/7p/p3n3/PP5P/8/1BPPPPP1/RN1BKQRN w GAga - 0 9 +epd rnbbkqr1/1pppppp1/7p/p3n3/PP5P/8/1BPPPPP1/RN1BKQRN w GAga - perft 1 23 perft 2 543 perft 3 12224 @@ -5663,7 +5663,7 @@ perft 5 7549008 perft 6 199883770 id 629 -epd r1bkqbrn/ppppp1pp/8/5p2/3nPP2/1P4N1/P1PP2PP/RNBKQBR1 w GAga - 1 9 +epd r1bkqbrn/ppppp1pp/8/5p2/3nPP2/1P4N1/P1PP2PP/RNBKQBR1 w GAga - perft 1 27 perft 2 751 perft 3 21158 @@ -5672,7 +5672,7 @@ perft 5 17989920 perft 6 527273615 id 630 -epd rnbkqr1b/1p1pp1pp/p4p1n/2p5/1P5P/N4P2/P1PPP1P1/R1BKQRNB w FAfa - 0 9 +epd rnbkqr1b/1p1pp1pp/p4p1n/2p5/1P5P/N4P2/P1PPP1P1/R1BKQRNB w FAfa - perft 1 21 perft 2 498 perft 3 11738 @@ -5681,7 +5681,7 @@ perft 5 7808375 perft 6 216224115 id 631 -epd rbnkbqrn/p1p3pp/1p1p4/B3pp2/3P2P1/6N1/PPP1PP1P/RBNK1QR1 w GAga - 0 9 +epd rbnkbqrn/p1p3pp/1p1p4/B3pp2/3P2P1/6N1/PPP1PP1P/RBNK1QR1 w GAga - perft 1 34 perft 2 977 perft 3 33464 @@ -5690,7 +5690,7 @@ perft 5 33318567 perft 6 978991050 id 632 -epd r1kbbqrn/ppp3pp/2np1p2/1P2p3/3P1P2/8/P1P1P1PP/RNKBBQRN w GAga - 0 9 +epd r1kbbqrn/ppp3pp/2np1p2/1P2p3/3P1P2/8/P1P1P1PP/RNKBBQRN w GAga - perft 1 32 perft 2 920 perft 3 28916 @@ -5699,7 +5699,7 @@ perft 5 26763259 perft 6 797524786 id 633 -epd rk1qbbrn/p2npppp/1p6/2p4Q/8/4P3/PPPP1PPP/RNK1B1RN w GA - 2 9 +epd rk1qbbrn/p2npppp/1p6/2p4Q/8/4P3/PPPP1PPP/RNK1B1RN w GA - perft 1 35 perft 2 657 perft 3 22359 @@ -5708,7 +5708,7 @@ perft 5 16662477 perft 6 419496845 id 634 -epd rnk1brnb/pp1p1pp1/8/q1p1p2p/5P2/NP6/P1PPP1PP/R1KQBRNB w FAfa - 1 9 +epd rnk1brnb/pp1p1pp1/8/q1p1p2p/5P2/NP6/P1PPP1PP/R1KQBRNB w FAfa - perft 1 26 perft 2 774 perft 3 20215 @@ -5717,7 +5717,7 @@ perft 5 16987110 perft 6 523437649 id 635 -epd rb1kqrbn/npp1ppp1/p7/3P3p/2PP4/8/PP3PPP/RBNKQRBN w FAfa - 0 9 +epd rb1kqrbn/npp1ppp1/p7/3P3p/2PP4/8/PP3PPP/RBNKQRBN w FAfa - perft 1 35 perft 2 775 perft 3 27395 @@ -5726,7 +5726,7 @@ perft 5 23983464 perft 6 625669222 id 636 -epd rnkb1rbn/pp1p2pp/8/2p1pp1q/P6P/1PN5/2PPPPP1/R1KBQRBN w FAfa - 1 9 +epd rnkb1rbn/pp1p2pp/8/2p1pp1q/P6P/1PN5/2PPPPP1/R1KBQRBN w FAfa - perft 1 22 perft 2 899 perft 3 21188 @@ -5735,7 +5735,7 @@ perft 5 21518343 perft 6 857951339 id 637 -epd rnkqrbbn/1pppp1p1/8/p2N1p1p/2P4P/8/PP1PPPP1/R1KQRBBN w EAea - 0 9 +epd rnkqrbbn/1pppp1p1/8/p2N1p1p/2P4P/8/PP1PPPP1/R1KQRBBN w EAea - perft 1 29 perft 2 585 perft 3 17571 @@ -5744,7 +5744,7 @@ perft 5 12238776 perft 6 299752383 id 638 -epd rnk1r1bb/pp1ppppp/1q4n1/2p5/5P1P/3PP3/PPP3P1/RNKQRNBB w EAea - 1 9 +epd rnk1r1bb/pp1ppppp/1q4n1/2p5/5P1P/3PP3/PPP3P1/RNKQRNBB w EAea - perft 1 27 perft 2 884 perft 3 24613 @@ -5753,7 +5753,7 @@ perft 5 23698701 perft 6 790239502 id 639 -epd bbrnkrqn/1ppp1p2/6pp/p3p3/5PP1/2PB4/PP1PP2P/B1RNKRQN w FCfc - 0 9 +epd bbrnkrqn/1ppp1p2/6pp/p3p3/5PP1/2PB4/PP1PP2P/B1RNKRQN w FCfc - perft 1 37 perft 2 693 perft 3 25425 @@ -5762,7 +5762,7 @@ perft 5 20138432 perft 6 481498664 id 640 -epd b1rbkrqn/ppp2ppp/1n2p3/3p4/6P1/2PP4/PP2PP1P/BRNBKRQN w FBf - 1 9 +epd b1rbkrqn/ppp2ppp/1n2p3/3p4/6P1/2PP4/PP2PP1P/BRNBKRQN w FBf - perft 1 21 perft 2 463 perft 3 10610 @@ -5771,7 +5771,7 @@ perft 5 6307276 perft 6 159025909 id 641 -epd brnkrb1n/1pp1p1pp/3p4/p1Nq1p2/2P5/8/PP1PPPPP/BRK1RBQN w eb - 2 9 +epd brnkrb1n/1pp1p1pp/3p4/p1Nq1p2/2P5/8/PP1PPPPP/BRK1RBQN w eb - perft 1 27 perft 2 725 perft 3 17842 @@ -5780,7 +5780,7 @@ perft 5 12604078 perft 6 362747791 id 642 -epd brn1r1nb/ppppkppp/4p3/8/2PP1P2/8/PP1KP1PP/BRN1RQNB w - - 1 9 +epd brn1r1nb/ppppkppp/4p3/8/2PP1P2/8/PP1KP1PP/BRN1RQNB w - - perft 1 25 perft 2 623 perft 3 16874 @@ -5789,7 +5789,7 @@ perft 5 12290985 perft 6 317097424 id 643 -epd rbb1krqn/1pp1pp1p/p3n1p1/3pP3/8/1PN5/P1PP1PPP/RBB1KRQN w FAfa d6 0 9 +epd rbb1krqn/1pp1pp1p/p3n1p1/3pP3/8/1PN5/P1PP1PPP/RBB1KRQN w FAfa d6 perft 1 23 perft 2 529 perft 3 12641 @@ -5798,7 +5798,7 @@ perft 5 7861413 perft 6 202594556 id 644 -epd r1bbkrqn/p1pppppp/8/4n3/1p5P/P2P2P1/1PP1PP2/RNBBKRQN w FAfa - 0 9 +epd r1bbkrqn/p1pppppp/8/4n3/1p5P/P2P2P1/1PP1PP2/RNBBKRQN w FAfa - perft 1 23 perft 2 571 perft 3 13133 @@ -5807,7 +5807,7 @@ perft 5 8699448 perft 6 243460643 id 645 -epd rnbkrbqn/p1pp1ppp/4p3/1p6/8/BPN3P1/P1PPPP1P/R2KRBQN w EAea - 2 9 +epd rnbkrbqn/p1pp1ppp/4p3/1p6/8/BPN3P1/P1PPPP1P/R2KRBQN w EAea - perft 1 29 perft 2 692 perft 3 20014 @@ -5816,7 +5816,7 @@ perft 5 14904192 perft 6 386694739 id 646 -epd rnbkrqn1/pppppp2/8/1Q2b1pp/P3P3/5P2/1PPP2PP/RNBKR1NB w EAea - 0 9 +epd rnbkrqn1/pppppp2/8/1Q2b1pp/P3P3/5P2/1PPP2PP/RNBKR1NB w EAea - perft 1 37 perft 2 1001 perft 3 36440 @@ -5825,7 +5825,7 @@ perft 5 35626426 perft 6 993747544 id 647 -epd rbnkbrqn/p1pppp2/7p/1p4pP/3P1P2/8/PPP1P1P1/RBNKBRQN w FAfa - 0 9 +epd rbnkbrqn/p1pppp2/7p/1p4pP/3P1P2/8/PPP1P1P1/RBNKBRQN w FAfa - perft 1 30 perft 2 564 perft 3 17143 @@ -5834,7 +5834,7 @@ perft 5 11859538 perft 6 293703269 id 648 -epd 1nkbbrqn/3ppppp/r1p5/pp6/8/4PP2/PPPPN1PP/RNKBBRQ1 w FAf - 2 9 +epd 1nkbbrqn/3ppppp/r1p5/pp6/8/4PP2/PPPPN1PP/RNKBBRQ1 w FAf - perft 1 26 perft 2 546 perft 3 14641 @@ -5843,7 +5843,7 @@ perft 5 9556962 perft 6 245137199 id 649 -epd rnkrbbq1/pppppnp1/7p/8/1B1Q1p2/3P1P2/PPP1P1PP/RNKR1B1N w DAda - 2 9 +epd rnkrbbq1/pppppnp1/7p/8/1B1Q1p2/3P1P2/PPP1P1PP/RNKR1B1N w DAda - perft 1 43 perft 2 887 perft 3 36240 @@ -5852,7 +5852,7 @@ perft 5 33185346 perft 6 851927292 id 650 -epd 1rkrbqnb/pppppp2/2n3p1/7p/3P3P/P4N2/1PP1PPP1/RNKRBQ1B w DAd - 0 9 +epd 1rkrbqnb/pppppp2/2n3p1/7p/3P3P/P4N2/1PP1PPP1/RNKRBQ1B w DAd - perft 1 26 perft 2 622 perft 3 16049 @@ -5861,7 +5861,7 @@ perft 5 10786140 perft 6 285233838 id 651 -epd rbnkr1bn/pp1pqp1p/2p1p3/6p1/3P4/7P/PPP1PPP1/RBNKRQBN w EAea - 0 9 +epd rbnkr1bn/pp1pqp1p/2p1p3/6p1/3P4/7P/PPP1PPP1/RBNKRQBN w EAea - perft 1 19 perft 2 566 perft 3 12257 @@ -5870,7 +5870,7 @@ perft 5 9107175 perft 6 293397389 id 652 -epd r1kbrqb1/pppp2pp/2n1p1n1/5p1B/4PP2/P7/1PPP2PP/RNK1RQBN w EAea - 2 9 +epd r1kbrqb1/pppp2pp/2n1p1n1/5p1B/4PP2/P7/1PPP2PP/RNK1RQBN w EAea - perft 1 39 perft 2 1359 perft 3 53626 @@ -5879,7 +5879,7 @@ perft 5 73871486 perft 6 2633945690 id 653 -epd rnkrqbbn/p1p3pp/1p1ppp2/8/1P6/3P2P1/PKP1PP1P/RN1RQBBN w da - 0 9 +epd rnkrqbbn/p1p3pp/1p1ppp2/8/1P6/3P2P1/PKP1PP1P/RN1RQBBN w da - perft 1 26 perft 2 776 perft 3 20735 @@ -5888,7 +5888,7 @@ perft 5 16884013 perft 6 503561996 id 654 -epd rnkrqnbb/ppp2p1p/3p4/4p1p1/3P3P/N1Q5/PPP1PPP1/R1KR1NBB w DAda - 0 9 +epd rnkrqnbb/ppp2p1p/3p4/4p1p1/3P3P/N1Q5/PPP1PPP1/R1KR1NBB w DAda - perft 1 40 perft 2 1175 perft 3 45637 @@ -5897,7 +5897,7 @@ perft 5 52620163 perft 6 1633655838 id 655 -epd bbrnkrn1/p1pppp2/1p6/6pp/3q4/1P3QP1/P1PPPP1P/BBRNKRN1 w FCfc - 0 9 +epd bbrnkrn1/p1pppp2/1p6/6pp/3q4/1P3QP1/P1PPPP1P/BBRNKRN1 w FCfc - perft 1 34 perft 2 1398 perft 3 45749 @@ -5906,7 +5906,7 @@ perft 5 57268492 perft 6 2059942014 id 656 -epd br1bkrnq/1p2pppp/pnp5/3p4/P1P5/5P2/1P1PPKPP/BRNB1RNQ w fb - 2 9 +epd br1bkrnq/1p2pppp/pnp5/3p4/P1P5/5P2/1P1PPKPP/BRNB1RNQ w fb - perft 1 24 perft 2 501 perft 3 12237 @@ -5915,7 +5915,7 @@ perft 5 7049659 perft 6 177940764 id 657 -epd brnkrbn1/pppppp1q/B6p/6p1/8/1P2PP2/P1PP2PP/BRNKR1NQ w EBeb - 0 9 +epd brnkrbn1/pppppp1q/B6p/6p1/8/1P2PP2/P1PP2PP/BRNKR1NQ w EBeb - perft 1 34 perft 2 815 perft 3 25868 @@ -5924,7 +5924,7 @@ perft 5 22006883 perft 6 639803952 id 658 -epd br1krnqb/pppppp1p/1n4p1/8/8/P2NN3/2PPPPPP/BR1K1RQB w Beb - 2 9 +epd br1krnqb/pppppp1p/1n4p1/8/8/P2NN3/2PPPPPP/BR1K1RQB w Beb - perft 1 37 perft 2 1029 perft 3 36748 @@ -5933,7 +5933,7 @@ perft 5 36214583 perft 6 1026195877 id 659 -epd rbbnkr1q/p1p2ppp/1p1ppn2/8/1PP4P/8/P2PPPP1/RBBNKRNQ w FAfa - 0 9 +epd rbbnkr1q/p1p2ppp/1p1ppn2/8/1PP4P/8/P2PPPP1/RBBNKRNQ w FAfa - perft 1 28 perft 2 755 perft 3 22623 @@ -5942,7 +5942,7 @@ perft 5 18972778 perft 6 513486101 id 660 -epd r1b1krnq/pp2pppp/1bn5/2pp4/4N3/5P2/PPPPPRPP/R1BBK1NQ w Afa - 0 9 +epd r1b1krnq/pp2pppp/1bn5/2pp4/4N3/5P2/PPPPPRPP/R1BBK1NQ w Afa - perft 1 24 perft 2 705 perft 3 17427 @@ -5951,7 +5951,7 @@ perft 5 13532966 perft 6 426443376 id 661 -epd 1nbkrbn1/rpppppqp/p7/6p1/4P3/3P2P1/PPP1KP1P/RNB1RBNQ w e - 1 9 +epd 1nbkrbn1/rpppppqp/p7/6p1/4P3/3P2P1/PPP1KP1P/RNB1RBNQ w e - perft 1 31 perft 2 800 perft 3 24748 @@ -5960,7 +5960,7 @@ perft 5 21193292 perft 6 625757852 id 662 -epd r1bkrnqb/pp3ppp/n1ppp3/8/1P5P/P7/R1PPPPP1/1NBKRNQB w Eea - 0 9 +epd r1bkrnqb/pp3ppp/n1ppp3/8/1P5P/P7/R1PPPPP1/1NBKRNQB w Eea - perft 1 21 perft 2 482 perft 3 11417 @@ -5969,7 +5969,7 @@ perft 5 7112890 perft 6 180378139 id 663 -epd rbnkbrnq/ppp1p2p/5p2/3p2p1/1B1P4/1N4P1/PPP1PP1P/RB1K1RNQ w FAfa - 0 9 +epd rbnkbrnq/ppp1p2p/5p2/3p2p1/1B1P4/1N4P1/PPP1PP1P/RB1K1RNQ w FAfa - perft 1 33 perft 2 780 perft 3 25532 @@ -5978,7 +5978,7 @@ perft 5 20756770 perft 6 535497008 id 664 -epd rnk1brnq/pp1ppppp/2p5/b7/8/1P2P2P/P1PP1PPQ/RNKBBRN1 w FAfa - 3 9 +epd rnk1brnq/pp1ppppp/2p5/b7/8/1P2P2P/P1PP1PPQ/RNKBBRN1 w FAfa - perft 1 29 perft 2 648 perft 3 19043 @@ -5987,7 +5987,7 @@ perft 5 13722785 perft 6 341389148 id 665 -epd rnkrbbnq/p1p3pp/5p2/1p1pp3/P7/1PN2P2/2PPP1PP/R1KRBBNQ w DAda - 0 9 +epd rnkrbbnq/p1p3pp/5p2/1p1pp3/P7/1PN2P2/2PPP1PP/R1KRBBNQ w DAda - perft 1 26 perft 2 827 perft 3 21865 @@ -5996,7 +5996,7 @@ perft 5 18916370 perft 6 589161126 id 666 -epd r1krbnqb/p1pp1ppp/2n1p3/8/1p4P1/PPP5/3PPP1P/RNKRBNQB w DAda - 1 9 +epd r1krbnqb/p1pp1ppp/2n1p3/8/1p4P1/PPP5/3PPP1P/RNKRBNQB w DAda - perft 1 25 perft 2 540 perft 3 14709 @@ -6005,7 +6005,7 @@ perft 5 9491817 perft 6 225389422 id 667 -epd rbnkrnbq/ppp1pp2/3p2p1/2N5/P6p/2P5/1P1PPPPP/RB1KRNBQ w EAea - 0 9 +epd rbnkrnbq/ppp1pp2/3p2p1/2N5/P6p/2P5/1P1PPPPP/RB1KRNBQ w EAea - perft 1 32 perft 2 790 perft 3 25107 @@ -6014,7 +6014,7 @@ perft 5 20906017 perft 6 578332225 id 668 -epd rnkbrn1q/1ppppppb/8/p4N1p/8/P1N5/1PPPPPPP/R1KBR1BQ w EAea - 0 9 +epd rnkbrn1q/1ppppppb/8/p4N1p/8/P1N5/1PPPPPPP/R1KBR1BQ w EAea - perft 1 31 perft 2 691 perft 3 20813 @@ -6023,7 +6023,7 @@ perft 5 15308408 perft 6 404129987 id 669 -epd rnkrnbbq/p1p2ppp/3pp3/1p6/6P1/4PQ1B/PPPP1P1P/RNKRN1B1 w DAda - 0 9 +epd rnkrnbbq/p1p2ppp/3pp3/1p6/6P1/4PQ1B/PPPP1P1P/RNKRN1B1 w DAda - perft 1 29 perft 2 558 perft 3 16800 @@ -6032,7 +6032,7 @@ perft 5 10825379 perft 6 246965507 id 670 -epd rnkrnqbb/pp2p1p1/3p3p/2p2p2/5P2/1P1N4/P1PPPQPP/RNKR2BB w DAda - 0 9 +epd rnkrnqbb/pp2p1p1/3p3p/2p2p2/5P2/1P1N4/P1PPPQPP/RNKR2BB w DAda - perft 1 29 perft 2 762 perft 3 23210 @@ -6041,7 +6041,7 @@ perft 5 20522675 perft 6 596067005 id 671 -epd bb1rknnr/ppqppppp/8/2p5/3P1N2/1P6/P1P1PPPP/BBQRKN1R w HDhd - 1 9 +epd bb1rknnr/ppqppppp/8/2p5/3P1N2/1P6/P1P1PPPP/BBQRKN1R w HDhd - perft 1 33 perft 2 963 perft 3 32279 @@ -6050,7 +6050,7 @@ perft 5 34552118 perft 6 1124738493 id 672 -epd bqrbknnr/ppp1p2p/8/3p1p2/5p2/P3N2P/1PPPP1P1/BQRBK1NR w HChc - 0 9 +epd bqrbknnr/ppp1p2p/8/3p1p2/5p2/P3N2P/1PPPP1P1/BQRBK1NR w HChc - perft 1 20 perft 2 398 perft 3 9009 @@ -6059,7 +6059,7 @@ perft 5 4834319 perft 6 113660536 id 673 -epd b1rk1bnr/qpp1pppp/p4n2/3p4/3PPP2/7N/PPP3PP/BQRKNB1R w HChc - 1 9 +epd b1rk1bnr/qpp1pppp/p4n2/3p4/3PPP2/7N/PPP3PP/BQRKNB1R w HChc - perft 1 25 perft 2 648 perft 3 16587 @@ -6068,7 +6068,7 @@ perft 5 12200870 perft 6 351766307 id 674 -epd bqkrnnrb/pppp2p1/4pp2/4P2p/6P1/7P/PPPP1P2/BQRKNNRB w GC - 1 9 +epd bqkrnnrb/pppp2p1/4pp2/4P2p/6P1/7P/PPPP1P2/BQRKNNRB w GC - perft 1 30 perft 2 493 perft 3 15118 @@ -6077,7 +6077,7 @@ perft 5 8786998 perft 6 181492621 id 675 -epd q1brknnr/1p1ppppp/p7/2p5/8/1PPP4/P2RPPPP/QBB1KNNR w Hhd - 0 9 +epd q1brknnr/1p1ppppp/p7/2p5/8/1PPP4/P2RPPPP/QBB1KNNR w Hhd - perft 1 25 perft 2 501 perft 3 13206 @@ -6086,7 +6086,7 @@ perft 5 7982978 perft 6 192717198 id 676 -epd qrb1k1nr/ppppb1pp/6n1/4ppN1/3P4/4N3/PPP1PPPP/QRBBK2R w HBhb - 2 9 +epd qrb1k1nr/ppppb1pp/6n1/4ppN1/3P4/4N3/PPP1PPPP/QRBBK2R w HBhb - perft 1 31 perft 2 872 perft 3 26191 @@ -6095,7 +6095,7 @@ perft 5 22493014 perft 6 646855304 id 677 -epd 1rbknbnr/1ppp1pp1/q6p/p3p3/5P2/2PPB3/PP2P1PP/QR1KNBNR w HBhb - 0 9 +epd 1rbknbnr/1ppp1pp1/q6p/p3p3/5P2/2PPB3/PP2P1PP/QR1KNBNR w HBhb - perft 1 28 perft 2 1020 perft 3 28147 @@ -6104,7 +6104,7 @@ perft 5 27484692 perft 6 947786800 id 678 -epd qrbk2rb/1ppp1ppp/5nn1/p3p3/1N6/P7/1PPPPPPP/QRB1KNRB w gb - 0 9 +epd qrbk2rb/1ppp1ppp/5nn1/p3p3/1N6/P7/1PPPPPPP/QRB1KNRB w gb - perft 1 23 perft 2 592 perft 3 14398 @@ -6113,7 +6113,7 @@ perft 5 10098215 perft 6 293988585 id 679 -epd qbrk1nnr/1pp1pppp/2b5/p2p4/P2P2P1/8/1PP1PP1P/QBKRBNNR w hc - 1 9 +epd qbrk1nnr/1pp1pppp/2b5/p2p4/P2P2P1/8/1PP1PP1P/QBKRBNNR w hc - perft 1 26 perft 2 654 perft 3 18103 @@ -6122,7 +6122,7 @@ perft 5 13740891 perft 6 373081138 id 680 -epd qrkbbnnr/ppp2p1p/4p3/3p2p1/P7/2PP4/1P2PPPP/QRKBBNNR w HBhb - 0 9 +epd qrkbbnnr/ppp2p1p/4p3/3p2p1/P7/2PP4/1P2PPPP/QRKBBNNR w HBhb - perft 1 25 perft 2 626 perft 3 16616 @@ -6131,7 +6131,7 @@ perft 5 12079406 perft 6 324006164 id 681 -epd qr1kbbnr/ppp1pp1p/4n1p1/2Pp4/6P1/4N3/PP1PPP1P/QRK1BBNR w HB d6 0 9 +epd qr1kbbnr/ppp1pp1p/4n1p1/2Pp4/6P1/4N3/PP1PPP1P/QRK1BBNR w HB d6 perft 1 26 perft 2 699 perft 3 18068 @@ -6140,7 +6140,7 @@ perft 5 13353359 perft 6 375702908 id 682 -epd qrk1b1rb/p1pppppp/3nnQ2/1p6/1P3P2/3P4/P1P1P1PP/1RKNBNRB w GBgb - 3 9 +epd qrk1b1rb/p1pppppp/3nnQ2/1p6/1P3P2/3P4/P1P1P1PP/1RKNBNRB w GBgb - perft 1 43 perft 2 1369 perft 3 55463 @@ -6149,7 +6149,7 @@ perft 5 71514365 perft 6 2427477375 id 683 -epd qbrk1nbr/pppp3p/5n2/4ppp1/3P1P2/4N3/PPP1P1PP/QBKRN1BR w hc - 0 9 +epd qbrk1nbr/pppp3p/5n2/4ppp1/3P1P2/4N3/PPP1P1PP/QBKRN1BR w hc - perft 1 25 perft 2 752 perft 3 20165 @@ -6158,7 +6158,7 @@ perft 5 17493373 perft 6 543180234 id 684 -epd qrkb1nbr/1pppppQp/3n4/p7/5p2/1P1N4/P1PPP1PP/1RKB1NBR w HBhb - 0 9 +epd qrkb1nbr/1pppppQp/3n4/p7/5p2/1P1N4/P1PPP1PP/1RKB1NBR w HBhb - perft 1 45 perft 2 946 perft 3 40100 @@ -6167,7 +6167,7 @@ perft 5 39736157 perft 6 1051910977 id 685 -epd qrk1nbbr/ppp1p1p1/4n2p/3p1p2/1P5P/3P2P1/P1P1PP2/QRKNNBBR w HBhb - 1 9 +epd qrk1nbbr/ppp1p1p1/4n2p/3p1p2/1P5P/3P2P1/P1P1PP2/QRKNNBBR w HBhb - perft 1 32 perft 2 770 perft 3 25367 @@ -6176,7 +6176,7 @@ perft 5 21717615 perft 6 577979364 id 686 -epd qrkn1rbb/pp2pppp/2p5/3p4/P2Qn1P1/1P6/2PPPP1P/1RKNNRBB w FBfb - 0 9 +epd qrkn1rbb/pp2pppp/2p5/3p4/P2Qn1P1/1P6/2PPPP1P/1RKNNRBB w FBfb - perft 1 38 perft 2 943 perft 3 35335 @@ -6185,7 +6185,7 @@ perft 5 31909835 perft 6 798405123 id 687 -epd bbrqknnr/ppp4p/3pp3/5pp1/4PP2/5Q2/PPPP2PP/BBR1KNNR w HChc - 0 9 +epd bbrqknnr/ppp4p/3pp3/5pp1/4PP2/5Q2/PPPP2PP/BBR1KNNR w HChc - perft 1 36 perft 2 843 perft 3 29974 @@ -6194,7 +6194,7 @@ perft 5 26828059 perft 6 723306114 id 688 -epd 1rqbkn1r/p1p1pppp/1p5n/P2p4/3Pb1P1/8/1PP1PP1P/BRQBKNNR w HBhb - 0 9 +epd 1rqbkn1r/p1p1pppp/1p5n/P2p4/3Pb1P1/8/1PP1PP1P/BRQBKNNR w HBhb - perft 1 23 perft 2 778 perft 3 19482 @@ -6203,7 +6203,7 @@ perft 5 17337683 perft 6 579112676 id 689 -epd br1knbnr/1qp1pppp/pp1p4/8/8/PP6/2PPPPPP/BRQKNBNR w HBhb - 2 9 +epd br1knbnr/1qp1pppp/pp1p4/8/8/PP6/2PPPPPP/BRQKNBNR w HBhb - perft 1 26 perft 2 697 perft 3 18835 @@ -6212,7 +6212,7 @@ perft 5 15280079 perft 6 473071890 id 690 -epd brqk2rb/ppppp1pp/4np2/8/2n5/3P1Q2/PP2PPPP/BR1KNNRB w GBgb - 0 9 +epd brqk2rb/ppppp1pp/4np2/8/2n5/3P1Q2/PP2PPPP/BR1KNNRB w GBgb - perft 1 32 perft 2 948 perft 3 30434 @@ -6221,7 +6221,7 @@ perft 5 29821322 perft 6 874251866 id 691 -epd r1bqknnr/pp1pp1p1/5p1p/2p1b2N/2P5/8/PPQPPPPP/RBB1K1NR w HAha - 0 9 +epd r1bqknnr/pp1pp1p1/5p1p/2p1b2N/2P5/8/PPQPPPPP/RBB1K1NR w HAha - perft 1 31 perft 2 785 perft 3 25549 @@ -6230,7 +6230,7 @@ perft 5 22244193 perft 6 592797491 id 692 -epd rqbbknnr/ppppp2p/5pp1/8/8/1P3PP1/PQPPP2P/R1BBKNNR w HAha - 0 9 +epd rqbbknnr/ppppp2p/5pp1/8/8/1P3PP1/PQPPP2P/R1BBKNNR w HAha - perft 1 23 perft 2 391 perft 3 10163 @@ -6239,7 +6239,7 @@ perft 5 5576671 perft 6 121267576 id 693 -epd rqbknbnr/1pp1p2p/p7/3p1pp1/7N/1PP5/P2PPPPP/RQBK1BNR w HAha - 0 9 +epd rqbknbnr/1pp1p2p/p7/3p1pp1/7N/1PP5/P2PPPPP/RQBK1BNR w HAha - perft 1 27 perft 2 676 perft 3 19606 @@ -6248,7 +6248,7 @@ perft 5 15955388 perft 6 448477218 id 694 -epd rqb1nnrb/2ppkppp/1p2p3/p7/2PPP3/1P6/P4PPP/RQBKNNRB w GA - 1 9 +epd rqb1nnrb/2ppkppp/1p2p3/p7/2PPP3/1P6/P4PPP/RQBKNNRB w GA - perft 1 31 perft 2 727 perft 3 22895 @@ -6257,7 +6257,7 @@ perft 5 18361051 perft 6 483248153 id 695 -epd rb1kbn1r/p1ppppp1/qp5n/7p/P7/RPP5/3PPPPP/1BQKBNNR w Hha - 2 9 +epd rb1kbn1r/p1ppppp1/qp5n/7p/P7/RPP5/3PPPPP/1BQKBNNR w Hha - perft 1 29 perft 2 837 perft 3 23815 @@ -6266,7 +6266,7 @@ perft 5 21279560 perft 6 682863811 id 696 -epd rqkbb1nr/p1p2ppp/1p1p2n1/3Np3/4P3/5N2/PPPP1PPP/RQKBB2R w HAha - 0 9 +epd rqkbb1nr/p1p2ppp/1p1p2n1/3Np3/4P3/5N2/PPPP1PPP/RQKBB2R w HAha - perft 1 28 perft 2 717 perft 3 20663 @@ -6275,7 +6275,7 @@ perft 5 16347343 perft 6 453153783 id 697 -epd rqknbbr1/p1pppp1p/1p3np1/8/4P3/2P2P1P/PP1P2P1/RQKNBBNR w HAa - 0 9 +epd rqknbbr1/p1pppp1p/1p3np1/8/4P3/2P2P1P/PP1P2P1/RQKNBBNR w HAa - perft 1 27 perft 2 650 perft 3 18231 @@ -6284,7 +6284,7 @@ perft 5 13847463 perft 6 383256006 id 698 -epd r1k1bnrb/1qpppppp/1p2n3/p7/1P5P/6P1/P1PPPP2/RQKNBNR1 w GAga - 1 9 +epd r1k1bnrb/1qpppppp/1p2n3/p7/1P5P/6P1/P1PPPP2/RQKNBNR1 w GAga - perft 1 24 perft 2 806 perft 3 20693 @@ -6293,7 +6293,7 @@ perft 5 19382263 perft 6 686009788 id 699 -epd rb1knnbr/1pp1ppp1/p2p3p/5q2/3B2P1/3P1P2/PPP1P2P/RBQKNN1R w HAha - 0 9 +epd rb1knnbr/1pp1ppp1/p2p3p/5q2/3B2P1/3P1P2/PPP1P2P/RBQKNN1R w HAha - perft 1 34 perft 2 1360 perft 3 44096 @@ -6302,7 +6302,7 @@ perft 5 51973672 perft 6 1837704407 id 700 -epd rqkb1nbr/p1p1ppp1/1p3n1p/2Qp4/8/2P5/PP1PPPPP/R1KBNNBR w HAha - 2 9 +epd rqkb1nbr/p1p1ppp1/1p3n1p/2Qp4/8/2P5/PP1PPPPP/R1KBNNBR w HAha - perft 1 39 perft 2 983 perft 3 38218 @@ -6311,7 +6311,7 @@ perft 5 36347815 perft 6 918801645 id 701 -epd rqknnbbr/2pppp2/pp5p/6p1/1P1P4/4PP2/P1P3PP/RQKNNBBR w HAha - 0 9 +epd rqknnbbr/2pppp2/pp5p/6p1/1P1P4/4PP2/P1P3PP/RQKNNBBR w HAha - perft 1 26 perft 2 628 perft 3 17638 @@ -6320,7 +6320,7 @@ perft 5 13787303 perft 6 386125234 id 702 -epd rqkn1rbb/1pp1pppp/p7/3p4/3Pn3/2P1PP2/PP4PP/RQKNNRBB w FAfa - 1 9 +epd rqkn1rbb/1pp1pppp/p7/3p4/3Pn3/2P1PP2/PP4PP/RQKNNRBB w FAfa - perft 1 20 perft 2 527 perft 3 12216 @@ -6329,7 +6329,7 @@ perft 5 8082183 perft 6 219311659 id 703 -epd bbrkqn1r/1pppppp1/5n2/p7/1PP2P1p/7N/P2PP1PP/BBRKQN1R w HChc - 1 9 +epd bbrkqn1r/1pppppp1/5n2/p7/1PP2P1p/7N/P2PP1PP/BBRKQN1R w HChc - perft 1 36 perft 2 963 perft 3 35291 @@ -6338,7 +6338,7 @@ perft 5 35907489 perft 6 1034223364 id 704 -epd brkbqn1r/p2ppppp/7n/1p6/P1p3PP/8/1PPPPP1N/BRKBQ1NR w HBhb - 0 9 +epd brkbqn1r/p2ppppp/7n/1p6/P1p3PP/8/1PPPPP1N/BRKBQ1NR w HBhb - perft 1 18 perft 2 583 perft 3 11790 @@ -6347,7 +6347,7 @@ perft 5 8858385 perft 6 304339862 id 705 -epd brkq1bnr/pp1ppp1p/8/2p2np1/P7/8/1PPPPPPP/BRKQNBNR w HBhb - 0 9 +epd brkq1bnr/pp1ppp1p/8/2p2np1/P7/8/1PPPPPPP/BRKQNBNR w HBhb - perft 1 19 perft 2 552 perft 3 11811 @@ -6356,7 +6356,7 @@ perft 5 8432183 perft 6 262293169 id 706 -epd brkqnnrb/1ppppppp/8/8/p3P3/5N2/PPPP1PPP/BRKQ1NRB w GBgb - 3 9 +epd brkqnnrb/1ppppppp/8/8/p3P3/5N2/PPPP1PPP/BRKQ1NRB w GBgb - perft 1 21 perft 2 397 perft 3 9653 @@ -6365,7 +6365,7 @@ perft 5 5489836 perft 6 128389738 id 707 -epd rbbkq1nr/1p2pppp/p1p3nB/3p4/1Q1P4/6N1/PPP1PPPP/RB1K2NR w HAha - 0 9 +epd rbbkq1nr/1p2pppp/p1p3nB/3p4/1Q1P4/6N1/PPP1PPPP/RB1K2NR w HAha - perft 1 40 perft 2 1132 perft 3 43404 @@ -6374,7 +6374,7 @@ perft 5 47425783 perft 6 1415578783 id 708 -epd rkbbq1nr/1pppp1p1/4np2/p6p/8/PP3P2/1KPPP1PP/R1BBQNNR w ha - 0 9 +epd rkbbq1nr/1pppp1p1/4np2/p6p/8/PP3P2/1KPPP1PP/R1BBQNNR w ha - perft 1 24 perft 2 596 perft 3 15220 @@ -6383,7 +6383,7 @@ perft 5 10822049 perft 6 302056813 id 709 -epd r1bqn1nr/pkpppp1p/1p4pb/8/PN6/R7/1PPPPPPP/1KBQ1BNR w H - 2 9 +epd r1bqn1nr/pkpppp1p/1p4pb/8/PN6/R7/1PPPPPPP/1KBQ1BNR w H - perft 1 33 perft 2 794 perft 3 25450 @@ -6392,7 +6392,7 @@ perft 5 20919309 perft 6 561073410 id 710 -epd rkb1nnrb/1pppq1pp/p4p2/4p3/5P2/1P1PB3/P1P1P1PP/RK1QNNRB w GAga - 0 9 +epd rkb1nnrb/1pppq1pp/p4p2/4p3/5P2/1P1PB3/P1P1P1PP/RK1QNNRB w GAga - perft 1 26 perft 2 625 perft 3 17050 @@ -6401,7 +6401,7 @@ perft 5 12515042 perft 6 342967558 id 711 -epd rbkqbn1r/pppp1p1p/2n1p1p1/8/8/1P1PP1N1/P1P2PPP/RBKQB1NR w HAha - 1 9 +epd rbkqbn1r/pppp1p1p/2n1p1p1/8/8/1P1PP1N1/P1P2PPP/RBKQB1NR w HAha - perft 1 30 perft 2 660 perft 3 20308 @@ -6410,7 +6410,7 @@ perft 5 15348335 perft 6 403323883 id 712 -epd rkqbb1n1/pppppppr/8/6np/5P2/8/PPPPP1PP/RKQBBNNR w HAa - 6 9 +epd rkqbb1n1/pppppppr/8/6np/5P2/8/PPPPP1PP/RKQBBNNR w HAa - perft 1 23 perft 2 500 perft 3 12154 @@ -6419,7 +6419,7 @@ perft 5 7519117 perft 6 196524441 id 713 -epd rkqnbbnr/ppppppp1/8/7p/3N4/6PP/PPPPPP2/RKQNBB1R w HAa - 0 9 +epd rkqnbbnr/ppppppp1/8/7p/3N4/6PP/PPPPPP2/RKQNBB1R w HAa - perft 1 24 perft 2 484 perft 3 12495 @@ -6428,7 +6428,7 @@ perft 5 7775173 perft 6 193947530 id 714 -epd rkqnb1rb/p1p1pppp/1p1p4/2n5/3P4/2P1N1N1/PP2PPPP/RKQ1B1RB w GAga - 0 9 +epd rkqnb1rb/p1p1pppp/1p1p4/2n5/3P4/2P1N1N1/PP2PPPP/RKQ1B1RB w GAga - perft 1 28 perft 2 1020 perft 3 29124 @@ -6437,7 +6437,7 @@ perft 5 30515456 perft 6 1073711823 id 715 -epd rbk1nnbr/1ppq1ppp/p2p4/4p3/P3B2P/2P5/1P1PPPP1/R1KQNNBR w HAha - 2 9 +epd rbk1nnbr/1ppq1ppp/p2p4/4p3/P3B2P/2P5/1P1PPPP1/R1KQNNBR w HAha - perft 1 38 perft 2 998 perft 3 37265 @@ -6446,7 +6446,7 @@ perft 5 38552638 perft 6 1139322479 id 716 -epd r1qbn1br/k1pppppp/6n1/pp6/5P1P/P7/1PPPP1PB/RKQBNN1R w HA - 1 9 +epd r1qbn1br/k1pppppp/6n1/pp6/5P1P/P7/1PPPP1PB/RKQBNN1R w HA - perft 1 22 perft 2 549 perft 3 12867 @@ -6455,7 +6455,7 @@ perft 5 8725809 perft 6 251613569 id 717 -epd rkqnn1br/pppp3p/4p1pb/5p2/P2P4/7P/1PP1PPPB/RKQNNB1R w HAha - 1 9 +epd rkqnn1br/pppp3p/4p1pb/5p2/P2P4/7P/1PP1PPPB/RKQNNB1R w HAha - perft 1 32 perft 2 659 perft 3 21249 @@ -6464,7 +6464,7 @@ perft 5 15434721 perft 6 365761521 id 718 -epd rk1nnrbb/p1p1pppp/1p6/3p1q2/P3P3/2NN4/1PPP1PPP/RKQ2RBB w FAfa - 3 9 +epd rk1nnrbb/p1p1pppp/1p6/3p1q2/P3P3/2NN4/1PPP1PPP/RKQ2RBB w FAfa - perft 1 29 perft 2 989 perft 3 29087 @@ -6473,7 +6473,7 @@ perft 5 29643404 perft 6 998848556 id 719 -epd bbrk1q1r/ppppppp1/3n4/7p/3Pn3/6PN/PPP1PPNP/BBRK1Q1R w HChc - 2 9 +epd bbrk1q1r/ppppppp1/3n4/7p/3Pn3/6PN/PPP1PPNP/BBRK1Q1R w HChc - perft 1 23 perft 2 712 perft 3 16551 @@ -6482,7 +6482,7 @@ perft 5 12995202 perft 6 411077508 id 720 -epd brkbnq1r/p1ppp2p/5ppn/1p6/5P2/1P1P2P1/P1P1P2P/BRKBNQNR w HBhb - 0 9 +epd brkbnq1r/p1ppp2p/5ppn/1p6/5P2/1P1P2P1/P1P1P2P/BRKBNQNR w HBhb - perft 1 28 perft 2 856 perft 3 24984 @@ -6491,7 +6491,7 @@ perft 5 23529352 perft 6 754501112 id 721 -epd br1k1bnr/ppppp1pp/4np2/1B2P2q/3P4/8/PPP2PPP/BRKNQ1NR w HB - 3 9 +epd br1k1bnr/ppppp1pp/4np2/1B2P2q/3P4/8/PPP2PPP/BRKNQ1NR w HB - perft 1 36 perft 2 1214 perft 3 40615 @@ -6500,7 +6500,7 @@ perft 5 45096834 perft 6 1470987023 id 722 -epd brk1qnrb/pnppp1p1/1p6/5p1p/8/5PPP/PPPPP1R1/BRKNQN1B w Bgb - 0 9 +epd brk1qnrb/pnppp1p1/1p6/5p1p/8/5PPP/PPPPP1R1/BRKNQN1B w Bgb - perft 1 22 perft 2 551 perft 3 13111 @@ -6509,7 +6509,7 @@ perft 5 9040545 perft 6 259643605 id 723 -epd rbbkn1nr/1ppp2pp/p3p3/2q2p2/3P4/6P1/PPPBPP1P/RB1KNQNR w HAha - 0 9 +epd rbbkn1nr/1ppp2pp/p3p3/2q2p2/3P4/6P1/PPPBPP1P/RB1KNQNR w HAha - perft 1 31 perft 2 1060 perft 3 31332 @@ -6518,7 +6518,7 @@ perft 5 30314172 perft 6 976268967 id 724 -epd rkbbn1nr/ppppp1pp/8/6N1/5p2/1q6/P1PPPPPP/RKBBN1QR w HAha - 0 9 +epd rkbbn1nr/ppppp1pp/8/6N1/5p2/1q6/P1PPPPPP/RKBBN1QR w HAha - perft 1 3 perft 2 72 perft 3 1919 @@ -6527,7 +6527,7 @@ perft 5 1400832 perft 6 39654253 id 725 -epd rkb2bnr/pp2pppp/2p1n3/3p4/q2P4/5NP1/PPP1PP1P/RKBNQBR1 w Aha - 0 9 +epd rkb2bnr/pp2pppp/2p1n3/3p4/q2P4/5NP1/PPP1PP1P/RKBNQBR1 w Aha - perft 1 29 perft 2 861 perft 3 24504 @@ -6536,7 +6536,7 @@ perft 5 22763215 perft 6 731511256 id 726 -epd rkbq1nrb/ppppppp1/7p/8/1P1n4/P4P1P/2PPP1P1/RKBNQNRB w GAga - 0 9 +epd rkbq1nrb/ppppppp1/7p/8/1P1n4/P4P1P/2PPP1P1/RKBNQNRB w GAga - perft 1 25 perft 2 672 perft 3 17631 @@ -6545,7 +6545,7 @@ perft 5 12954224 perft 6 361237536 id 727 -epd rbknb1nr/ppp1qp1p/6p1/3pp3/3P3P/2B1P3/PPP2PP1/RBKN1QNR w HAha - 1 9 +epd rbknb1nr/ppp1qp1p/6p1/3pp3/3P3P/2B1P3/PPP2PP1/RBKN1QNR w HAha - perft 1 27 perft 2 857 perft 3 24688 @@ -6554,7 +6554,7 @@ perft 5 23790033 perft 6 768247869 id 728 -epd rknbbq1r/p1pppppp/1p2N3/8/3n4/2P5/PP1PPPPP/RK1BBQNR w HAha - 4 9 +epd rknbbq1r/p1pppppp/1p2N3/8/3n4/2P5/PP1PPPPP/RK1BBQNR w HAha - perft 1 29 perft 2 763 perft 3 22138 @@ -6563,7 +6563,7 @@ perft 5 16926075 perft 6 447896703 id 729 -epd r1nqbbnr/1pppp1pp/1k6/p4p2/8/4P3/PPPP1PPP/RKN1BBNR w HA - 0 9 +epd r1nqbbnr/1pppp1pp/1k6/p4p2/8/4P3/PPPP1PPP/RKN1BBNR w HA - perft 1 26 perft 2 658 perft 3 17302 @@ -6572,7 +6572,7 @@ perft 5 12380488 perft 6 349047256 id 730 -epd rkn2qrb/ppp1pppp/6n1/1b1p4/1P6/4PPB1/P1PP2PP/RKNQ1NRB w GAga - 3 9 +epd rkn2qrb/ppp1pppp/6n1/1b1p4/1P6/4PPB1/P1PP2PP/RKNQ1NRB w GAga - perft 1 23 perft 2 574 perft 3 14070 @@ -6581,7 +6581,7 @@ perft 5 9501401 perft 6 263870337 id 731 -epd rbkn2br/ppppp1p1/4np1p/1P5q/8/2P1N3/P2PPPPP/RBK1QNBR w HAha - 1 9 +epd rbkn2br/ppppp1p1/4np1p/1P5q/8/2P1N3/P2PPPPP/RBK1QNBR w HAha - perft 1 29 perft 2 992 perft 3 29506 @@ -6590,7 +6590,7 @@ perft 5 30148787 perft 6 1045942540 id 732 -epd 1knbqnbr/1ppppp1p/r5p1/p7/7P/2PN2P1/PP1PPP2/RK1BQNBR w HAh - 2 9 +epd 1knbqnbr/1ppppp1p/r5p1/p7/7P/2PN2P1/PP1PPP2/RK1BQNBR w HAh - perft 1 26 perft 2 698 perft 3 19395 @@ -6599,7 +6599,7 @@ perft 5 14848229 perft 6 402599313 id 733 -epd rk1qnbbr/pnpppp1p/6p1/1p6/3P4/1P6/P1P1PPPP/RKNQNBBR w HAha - 1 9 +epd rk1qnbbr/pnpppp1p/6p1/1p6/3P4/1P6/P1P1PPPP/RKNQNBBR w HAha - perft 1 20 perft 2 480 perft 3 11159 @@ -6608,7 +6608,7 @@ perft 5 7425917 perft 6 203194521 id 734 -epd rknqnrbb/pp1p2p1/5p1p/2p1p3/2P1P3/P2P4/1P3PPP/RKNQNRBB w FAfa - 0 9 +epd rknqnrbb/pp1p2p1/5p1p/2p1p3/2P1P3/P2P4/1P3PPP/RKNQNRBB w FAfa - perft 1 26 perft 2 679 perft 3 18116 @@ -6617,7 +6617,7 @@ perft 5 13790137 perft 6 392629571 id 735 -epd bbrk2qr/pp1p1ppp/3n2n1/2p1p3/3P1P2/6N1/PPP1P1PP/BBRKN1QR w HChc - 0 9 +epd bbrk2qr/pp1p1ppp/3n2n1/2p1p3/3P1P2/6N1/PPP1P1PP/BBRKN1QR w HChc - perft 1 26 perft 2 790 perft 3 21521 @@ -6626,7 +6626,7 @@ perft 5 19259490 perft 6 617563700 id 736 -epd b1krnnqr/1p1ppppp/p1p5/b6B/P7/4P1N1/1PPP1PPP/BRK1N1QR w HB - 2 9 +epd b1krnnqr/1p1ppppp/p1p5/b6B/P7/4P1N1/1PPP1PPP/BRK1N1QR w HB - perft 1 26 perft 2 625 perft 3 16451 @@ -6635,7 +6635,7 @@ perft 5 11490615 perft 6 304805107 id 737 -epd 1rknnbqr/3ppppp/p7/1pp5/4b2P/P4P2/1PPPP1PR/BRKNNBQ1 w Bhb - 1 9 +epd 1rknnbqr/3ppppp/p7/1pp5/4b2P/P4P2/1PPPP1PR/BRKNNBQ1 w Bhb - perft 1 24 perft 2 757 perft 3 19746 @@ -6644,7 +6644,7 @@ perft 5 17275100 perft 6 544309489 id 738 -epd br1nn1rb/pppkpqpp/3p1p2/8/PP6/4N3/1KPPPPPP/BR2NQRB w - - 3 9 +epd br1nn1rb/pppkpqpp/3p1p2/8/PP6/4N3/1KPPPPPP/BR2NQRB w - - perft 1 24 perft 2 682 perft 3 17129 @@ -6653,7 +6653,7 @@ perft 5 13057308 perft 6 375033550 id 739 -epd rbbkn1qr/pppp2p1/6np/4pp2/7N/7P/PPPPPPPR/RBBK1NQ1 w Aha - 0 9 +epd rbbkn1qr/pppp2p1/6np/4pp2/7N/7P/PPPPPPPR/RBBK1NQ1 w Aha - perft 1 22 perft 2 586 perft 3 14158 @@ -6662,7 +6662,7 @@ perft 5 10607781 perft 6 324452612 id 740 -epd rk1bn1qr/pppbpppp/4n3/4p3/4P3/5P2/PPPP2PP/RKBB1NQR w HAha - 1 9 +epd rk1bn1qr/pppbpppp/4n3/4p3/4P3/5P2/PPPP2PP/RKBB1NQR w HAha - perft 1 22 perft 2 530 perft 3 13440 @@ -6671,7 +6671,7 @@ perft 5 9514787 perft 6 259898748 id 741 -epd rkbnnbqr/1ppp1ppp/p7/4p3/8/QP3P2/P1PPP1PP/RKBNNB1R w HAha - 0 9 +epd rkbnnbqr/1ppp1ppp/p7/4p3/8/QP3P2/P1PPP1PP/RKBNNB1R w HAha - perft 1 29 perft 2 705 perft 3 21511 @@ -6680,7 +6680,7 @@ perft 5 17524731 perft 6 472356665 id 742 -epd 1kbnnqrb/1pp1p1pp/r4p2/p2p4/N4P2/3P4/PPP1P1PP/RKB1NQRB w GAg - 2 9 +epd 1kbnnqrb/1pp1p1pp/r4p2/p2p4/N4P2/3P4/PPP1P1PP/RKB1NQRB w GAg - perft 1 21 perft 2 623 perft 3 14979 @@ -6689,7 +6689,7 @@ perft 5 11601134 perft 6 343214006 id 743 -epd rbknbn1r/pppp1p1p/4p1q1/8/P1P3Pp/8/1P1PPP2/RBKNBNQR w HAha - 0 9 +epd rbknbn1r/pppp1p1p/4p1q1/8/P1P3Pp/8/1P1PPP2/RBKNBNQR w HAha - perft 1 30 perft 2 813 perft 3 24959 @@ -6698,7 +6698,7 @@ perft 5 23379040 perft 6 692576573 id 744 -epd rk1bb1qr/2pppppp/p2nn3/1p4P1/6QP/8/PPPPPP2/RKNBBN1R w HAha - 2 9 +epd rk1bb1qr/2pppppp/p2nn3/1p4P1/6QP/8/PPPPPP2/RKNBBN1R w HAha - perft 1 36 perft 2 857 perft 3 30124 @@ -6707,7 +6707,7 @@ perft 5 26485812 perft 6 696999449 id 745 -epd rkn1bbqr/p2ppppp/2p1n3/1p6/4PP2/6PP/PPPP4/RKNNBBQR w HAha - 0 9 +epd rkn1bbqr/p2ppppp/2p1n3/1p6/4PP2/6PP/PPPP4/RKNNBBQR w HAha - perft 1 33 perft 2 687 perft 3 22744 @@ -6716,7 +6716,7 @@ perft 5 17101732 perft 6 412778368 id 746 -epd rkn1bqrb/pnp1pppp/3p4/8/Pp6/1N2NP2/1PPPP1PP/RK2BQRB w GAga - 0 9 +epd rkn1bqrb/pnp1pppp/3p4/8/Pp6/1N2NP2/1PPPP1PP/RK2BQRB w GAga - perft 1 28 perft 2 591 perft 3 17174 @@ -6725,7 +6725,7 @@ perft 5 12182448 perft 6 312575205 id 747 -epd rbk1n1br/ppp1ppqp/2n5/2Np2p1/8/2P5/PPBPPPPP/R1KN1QBR w HAha - 4 9 +epd rbk1n1br/ppp1ppqp/2n5/2Np2p1/8/2P5/PPBPPPPP/R1KN1QBR w HAha - perft 1 35 perft 2 930 perft 3 30663 @@ -6734,7 +6734,7 @@ perft 5 27160490 perft 6 780616047 id 748 -epd rknbn1br/1ppp1ppp/p3p3/8/1q6/2P2N1P/P2PPPP1/RKNB1QBR w HAha - 0 9 +epd rknbn1br/1ppp1ppp/p3p3/8/1q6/2P2N1P/P2PPPP1/RKNB1QBR w HAha - perft 1 4 perft 2 157 perft 3 3697 @@ -6743,7 +6743,7 @@ perft 5 3454704 perft 6 125373395 id 749 -epd rkn1qbbr/pp3ppp/4n3/2ppp3/4P1P1/P2P4/1PP2P1P/RKNNQBBR w HAha - 0 9 +epd rkn1qbbr/pp3ppp/4n3/2ppp3/4P1P1/P2P4/1PP2P1P/RKNNQBBR w HAha - perft 1 28 perft 2 840 perft 3 24437 @@ -6752,7 +6752,7 @@ perft 5 23200961 perft 6 756489357 id 750 -epd rkn1qrbb/pp1ppp2/2p1n1p1/7p/2P2P1P/6P1/PP1PP3/RKNNQRBB w FAfa - 1 9 +epd rkn1qrbb/pp1ppp2/2p1n1p1/7p/2P2P1P/6P1/PP1PP3/RKNNQRBB w FAfa - perft 1 32 perft 2 867 perft 3 27595 @@ -6761,7 +6761,7 @@ perft 5 24485663 perft 6 688115847 id 751 -epd b1rknnrq/bpppp1p1/p6p/5p1P/6P1/4N3/PPPPPP2/BBRKN1RQ w GCgc - 1 9 +epd b1rknnrq/bpppp1p1/p6p/5p1P/6P1/4N3/PPPPPP2/BBRKN1RQ w GCgc - perft 1 33 perft 2 851 perft 3 28888 @@ -6770,7 +6770,7 @@ perft 5 26686205 perft 6 731944177 id 752 -epd brkb1nr1/pppppp2/3n2pp/3B4/1P6/4P3/PqPP1PPP/BRK1NNRQ w GBgb - 2 9 +epd brkb1nr1/pppppp2/3n2pp/3B4/1P6/4P3/PqPP1PPP/BRK1NNRQ w GBgb - perft 1 4 perft 2 98 perft 3 2965 @@ -6779,7 +6779,7 @@ perft 5 2352530 perft 6 64251468 id 753 -epd brk1nbrq/1ppppn1p/6p1/p4p2/P5P1/5R2/1PPPPP1P/BRKNNB1Q w Bgb - 0 9 +epd brk1nbrq/1ppppn1p/6p1/p4p2/P5P1/5R2/1PPPPP1P/BRKNNB1Q w Bgb - perft 1 29 perft 2 922 perft 3 27709 @@ -6788,7 +6788,7 @@ perft 5 27463717 perft 6 888881062 id 754 -epd brkn1rqb/1p1ppppp/3n4/p1p5/1P3P2/8/PNPPP1PP/BR1KNRQB w fb - 1 9 +epd brkn1rqb/1p1ppppp/3n4/p1p5/1P3P2/8/PNPPP1PP/BR1KNRQB w fb - perft 1 29 perft 2 633 perft 3 19399 @@ -6797,7 +6797,7 @@ perft 5 15076198 perft 6 396737074 id 755 -epd rb1k1nrq/pbp1pppp/1p1p1n2/8/5P2/4NN1P/PPPPP1P1/RBBK2RQ w GAga - 2 9 +epd rb1k1nrq/pbp1pppp/1p1p1n2/8/5P2/4NN1P/PPPPP1P1/RBBK2RQ w GAga - perft 1 28 perft 2 841 perft 3 24056 @@ -6806,7 +6806,7 @@ perft 5 20772996 perft 6 613798447 id 756 -epd rkbbnnrq/p1pp3p/4p1p1/1p3p2/P6P/1P6/1BPPPPP1/RK1BNNRQ w GAga - 0 9 +epd rkbbnnrq/p1pp3p/4p1p1/1p3p2/P6P/1P6/1BPPPPP1/RK1BNNRQ w GAga - perft 1 33 perft 2 957 perft 3 30668 @@ -6815,7 +6815,7 @@ perft 5 29735654 perft 6 903933626 id 757 -epd rk2nbrq/p1ppppp1/bpn5/7p/6P1/2N2P2/PPPPP1QP/RKB1NBR1 w GAga - 2 9 +epd rk2nbrq/p1ppppp1/bpn5/7p/6P1/2N2P2/PPPPP1QP/RKB1NBR1 w GAga - perft 1 24 perft 2 687 perft 3 18206 @@ -6824,7 +6824,7 @@ perft 5 15518417 perft 6 484217179 id 758 -epd rkbn1r1b/pp1pppnp/6q1/2p3p1/5P1P/4N3/PPPPP1P1/RKB1NRQB w FAfa - 1 9 +epd rkbn1r1b/pp1pppnp/6q1/2p3p1/5P1P/4N3/PPPPP1P1/RKB1NRQB w FAfa - perft 1 23 perft 2 831 perft 3 21254 @@ -6833,7 +6833,7 @@ perft 5 21126103 perft 6 744755212 id 759 -epd rbknb1rq/ppp1p1p1/3pnp1p/8/6PP/2PP4/PP2PP2/RBKNBNRQ w GAga - 0 9 +epd rbknb1rq/ppp1p1p1/3pnp1p/8/6PP/2PP4/PP2PP2/RBKNBNRQ w GAga - perft 1 31 perft 2 838 perft 3 26800 @@ -6842,7 +6842,7 @@ perft 5 24008129 perft 6 677776408 id 760 -epd rknbb1rq/p1pn1ppp/4p3/1p1p4/2P5/1P2N1P1/P2PPP1P/RKNBB1RQ w GAga - 1 9 +epd rknbb1rq/p1pn1ppp/4p3/1p1p4/2P5/1P2N1P1/P2PPP1P/RKNBB1RQ w GAga - perft 1 29 perft 2 830 perft 3 24798 @@ -6851,7 +6851,7 @@ perft 5 22243832 perft 6 660040360 id 761 -epd rk1nbbrq/pp1p1ppp/3n4/P3p3/2p4P/8/1PPPPPP1/RKNNBBRQ w GAga - 1 9 +epd rk1nbbrq/pp1p1ppp/3n4/P3p3/2p4P/8/1PPPPPP1/RKNNBBRQ w GAga - perft 1 24 perft 2 484 perft 3 12776 @@ -6860,7 +6860,7 @@ perft 5 8379748 perft 6 214004367 id 762 -epd rknnbr1b/ppp2pqp/3p4/4p1p1/7P/3P1P2/PPP1P1P1/RKNNBRQB w FAfa - 0 9 +epd rknnbr1b/ppp2pqp/3p4/4p1p1/7P/3P1P2/PPP1P1P1/RKNNBRQB w FAfa - perft 1 32 perft 2 838 perft 3 26408 @@ -6869,7 +6869,7 @@ perft 5 23472124 perft 6 699211365 id 763 -epd rb1k1rbq/ppppN1pp/2nn4/5p2/7P/8/PPPPPPP1/RBK1NRBQ w FA - 1 9 +epd rb1k1rbq/ppppN1pp/2nn4/5p2/7P/8/PPPPPPP1/RBK1NRBQ w FA - perft 1 27 perft 2 800 perft 3 22785 @@ -6878,7 +6878,7 @@ perft 5 20804424 perft 6 660917073 id 764 -epd r1nbnrbq/kppppp1p/6p1/8/p1PP1P2/4P3/PP4PP/RKNBNRBQ w FA - 1 9 +epd r1nbnrbq/kppppp1p/6p1/8/p1PP1P2/4P3/PP4PP/RKNBNRBQ w FA - perft 1 28 perft 2 757 perft 3 21198 @@ -6887,7 +6887,7 @@ perft 5 17180857 perft 6 507618340 id 765 -epd rkn1rbbq/p1pppppp/2n5/1pP5/8/1N2P3/PP1P1PPP/RK1NRBBQ w EAea - 1 9 +epd rkn1rbbq/p1pppppp/2n5/1pP5/8/1N2P3/PP1P1PPP/RK1NRBBQ w EAea - perft 1 22 perft 2 483 perft 3 11890 @@ -6896,7 +6896,7 @@ perft 5 7497674 perft 6 191130942 id 766 -epd rknnrqbb/2pppppp/8/p7/Np3P2/3P4/PPP1P1PP/RKN1RQBB w EAea - 0 9 +epd rknnrqbb/2pppppp/8/p7/Np3P2/3P4/PPP1P1PP/RKN1RQBB w EAea - perft 1 25 perft 2 536 perft 3 14456 @@ -6905,7 +6905,7 @@ perft 5 9694947 perft 6 245669668 id 767 -epd bb1rknrn/1qppppp1/1p4B1/p6N/8/2P5/PP1PPPPP/B1QRK1RN w GDgd - 1 9 +epd bb1rknrn/1qppppp1/1p4B1/p6N/8/2P5/PP1PPPPP/B1QRK1RN w GDgd - perft 1 32 perft 2 715 perft 3 22421 @@ -6914,7 +6914,7 @@ perft 5 17860156 perft 6 502410909 id 768 -epd b1rbknrn/qpp1ppp1/p6p/3p4/2P5/1P1P1P2/P3P1PP/BQRBKNRN w GCgc - 0 9 +epd b1rbknrn/qpp1ppp1/p6p/3p4/2P5/1P1P1P2/P3P1PP/BQRBKNRN w GCgc - perft 1 30 perft 2 818 perft 3 24421 @@ -6923,7 +6923,7 @@ perft 5 20981488 perft 6 611986786 id 769 -epd bqkrnbrn/1pp1pp1p/p7/1B1p2p1/4P3/7P/PPPP1PP1/BQKRN1RN w - - 0 9 +epd bqkrnbrn/1pp1pp1p/p7/1B1p2p1/4P3/7P/PPPP1PP1/BQKRN1RN w - - perft 1 28 perft 2 676 perft 3 18366 @@ -6932,7 +6932,7 @@ perft 5 13126287 perft 6 363765666 id 770 -epd bqrknrnb/1p2ppp1/p1pp3p/8/3P1P2/1PP5/P3P1PP/BQRKNRNB w FCfc - 0 9 +epd bqrknrnb/1p2ppp1/p1pp3p/8/3P1P2/1PP5/P3P1PP/BQRKNRNB w FCfc - perft 1 31 perft 2 646 perft 3 20686 @@ -6941,7 +6941,7 @@ perft 5 14984618 perft 6 349082278 id 771 -epd qbbrkn1r/pppppp1p/8/6p1/2P1Pn1P/6N1/PP1P1PP1/QBBRKNR1 w GDd - 3 9 +epd qbbrkn1r/pppppp1p/8/6p1/2P1Pn1P/6N1/PP1P1PP1/QBBRKNR1 w GDd - perft 1 20 perft 2 532 perft 3 11581 @@ -6950,7 +6950,7 @@ perft 5 7512432 perft 6 202967948 id 772 -epd 1rbbknr1/p1ppp1pp/1pq2pn1/8/3P4/P3P3/QPP2PPP/1RBBKNRN w GBgb - 3 9 +epd 1rbbknr1/p1ppp1pp/1pq2pn1/8/3P4/P3P3/QPP2PPP/1RBBKNRN w GBgb - perft 1 31 perft 2 1002 perft 3 30581 @@ -6959,7 +6959,7 @@ perft 5 30642468 perft 6 1009228283 id 773 -epd qrbkn1rn/pppp1ppp/8/6b1/P1P1Pp2/8/1P1P2PP/QRBKNBRN w GBgb - 0 9 +epd qrbkn1rn/pppp1ppp/8/6b1/P1P1Pp2/8/1P1P2PP/QRBKNBRN w GBgb - perft 1 22 perft 2 505 perft 3 12447 @@ -6968,7 +6968,7 @@ perft 5 8192621 perft 6 214730959 id 774 -epd qrbk1rnb/p2ppp1p/5n2/1pp3p1/8/7P/PPPPPPPN/QRBKR1NB w Bfb - 0 9 +epd qrbk1rnb/p2ppp1p/5n2/1pp3p1/8/7P/PPPPPPPN/QRBKR1NB w Bfb - perft 1 20 perft 2 619 perft 3 13448 @@ -6977,7 +6977,7 @@ perft 5 10571176 perft 6 369603424 id 775 -epd qbrkb1r1/ppp2ppp/3pn1n1/P3p3/4P3/3P4/1PP2PPP/QBRKBNRN w GCgc - 1 9 +epd qbrkb1r1/ppp2ppp/3pn1n1/P3p3/4P3/3P4/1PP2PPP/QBRKBNRN w GCgc - perft 1 26 perft 2 755 perft 3 20596 @@ -6986,7 +6986,7 @@ perft 5 17164382 perft 6 510878835 id 776 -epd qrkbb1r1/ppp1pnpp/3p2n1/5p2/1P3P2/2Q3N1/P1PPP1PP/1RKBB1RN w GBgb - 0 9 +epd qrkbb1r1/ppp1pnpp/3p2n1/5p2/1P3P2/2Q3N1/P1PPP1PP/1RKBB1RN w GBgb - perft 1 35 perft 2 918 perft 3 32244 @@ -6995,7 +6995,7 @@ perft 5 30933394 perft 6 867833733 id 777 -epd qrknbbrn/ppp1ppp1/8/7p/2Bp4/4PPP1/PPPP3P/QRKNB1RN w GBgb - 0 9 +epd qrknbbrn/ppp1ppp1/8/7p/2Bp4/4PPP1/PPPP3P/QRKNB1RN w GBgb - perft 1 27 perft 2 593 perft 3 16168 @@ -7004,7 +7004,7 @@ perft 5 10422676 perft 6 258348640 id 778 -epd qrk1brnb/ppppp3/4n2p/5pp1/2PP4/2N4P/PP2PPP1/QRK1BRNB w FBfb - 2 9 +epd qrk1brnb/ppppp3/4n2p/5pp1/2PP4/2N4P/PP2PPP1/QRK1BRNB w FBfb - perft 1 24 perft 2 672 perft 3 17447 @@ -7013,7 +7013,7 @@ perft 5 13765777 perft 6 414930519 id 779 -epd qbrknrb1/p2ppppp/2p3n1/8/p4P2/6PP/1PPPP3/QBRKNRBN w FCfc - 0 9 +epd qbrknrb1/p2ppppp/2p3n1/8/p4P2/6PP/1PPPP3/QBRKNRBN w FCfc - perft 1 29 perft 2 759 perft 3 23235 @@ -7022,7 +7022,7 @@ perft 5 20416668 perft 6 584870558 id 780 -epd 1rkb1rbn/p1pp1ppp/3np3/1p6/4qP2/3NB3/PPPPPRPP/QRKB3N w Bfb - 0 9 +epd 1rkb1rbn/p1pp1ppp/3np3/1p6/4qP2/3NB3/PPPPPRPP/QRKB3N w Bfb - perft 1 22 perft 2 923 perft 3 22585 @@ -7031,7 +7031,7 @@ perft 5 24049880 perft 6 957218571 id 781 -epd 1rknrbbn/p1pp1p1p/8/1p2p1p1/4qPP1/2P5/PP1PP1BP/QRKNR1BN w EBeb - 0 9 +epd 1rknrbbn/p1pp1p1p/8/1p2p1p1/4qPP1/2P5/PP1PP1BP/QRKNR1BN w EBeb - perft 1 28 perft 2 1309 perft 3 36355 @@ -7040,7 +7040,7 @@ perft 5 44576409 perft 6 1846382333 id 782 -epd qrk1rn1b/ppppp2p/4n3/3b1pp1/4P2P/5BP1/PPPP1P2/QRKNRNB1 w EBeb - 3 9 +epd qrk1rn1b/ppppp2p/4n3/3b1pp1/4P2P/5BP1/PPPP1P2/QRKNRNB1 w EBeb - perft 1 26 perft 2 839 perft 3 22189 @@ -7049,7 +7049,7 @@ perft 5 19978260 perft 6 661207281 id 783 -epd bbrqk1rn/pp1ppppp/8/2p5/2P1P3/5n1P/PPBP1PP1/B1RQKNRN w GCgc - 1 9 +epd bbrqk1rn/pp1ppppp/8/2p5/2P1P3/5n1P/PPBP1PP1/B1RQKNRN w GCgc - perft 1 3 perft 2 95 perft 3 2690 @@ -7058,7 +7058,7 @@ perft 5 2518864 perft 6 80775549 id 784 -epd brqbk2n/pppppprp/8/6p1/1P3n2/5P2/P1PPP1PP/R1QBKNRN w Gb - 2 9 +epd brqbk2n/pppppprp/8/6p1/1P3n2/5P2/P1PPP1PP/R1QBKNRN w Gb - perft 1 22 perft 2 593 perft 3 13255 @@ -7067,7 +7067,7 @@ perft 5 8922397 perft 6 253271592 id 785 -epd brqknbr1/pp3ppp/3p2n1/2p1p3/2P5/5P2/PPKPP1PP/BRQ1NBRN w gb - 0 9 +epd brqknbr1/pp3ppp/3p2n1/2p1p3/2P5/5P2/PPKPP1PP/BRQ1NBRN w gb - perft 1 21 perft 2 590 perft 3 13190 @@ -7076,7 +7076,7 @@ perft 5 9581695 perft 6 304103516 id 786 -epd 1rqknrnb/2pp1ppp/p3p3/1p6/P2P4/5bP1/1PP1PP1P/BRQKNRNB w FBfb - 0 9 +epd 1rqknrnb/2pp1ppp/p3p3/1p6/P2P4/5bP1/1PP1PP1P/BRQKNRNB w FBfb - perft 1 24 perft 2 737 perft 3 20052 @@ -7085,7 +7085,7 @@ perft 5 17948681 perft 6 536330341 id 787 -epd rbb1k1rn/p1pqpppp/6n1/1p1p4/5P2/3PP3/PPP1K1PP/RBBQ1NRN w ga - 3 9 +epd rbb1k1rn/p1pqpppp/6n1/1p1p4/5P2/3PP3/PPP1K1PP/RBBQ1NRN w ga - perft 1 24 perft 2 694 perft 3 16773 @@ -7094,7 +7094,7 @@ perft 5 13094823 perft 6 419402704 id 788 -epd rqbbknr1/1ppp2pp/p5n1/4pp2/P7/1PP5/1Q1PPPPP/R1BBKNRN w GAga - 0 9 +epd rqbbknr1/1ppp2pp/p5n1/4pp2/P7/1PP5/1Q1PPPPP/R1BBKNRN w GAga - perft 1 24 perft 2 600 perft 3 15347 @@ -7103,7 +7103,7 @@ perft 5 11029596 perft 6 308553169 id 789 -epd rqbknbrn/2pppppp/6Q1/pp6/8/2P5/PP1PPPPP/R1BKNBRN w GAga - 2 9 +epd rqbknbrn/2pppppp/6Q1/pp6/8/2P5/PP1PPPPP/R1BKNBRN w GAga - perft 1 40 perft 2 949 perft 3 34100 @@ -7112,7 +7112,7 @@ perft 5 31296485 perft 6 881529007 id 790 -epd rqbknr1b/pp1ppp2/2p2n1p/6p1/8/3P1PPP/PPP1P3/RQBKNRNB w FAfa - 0 9 +epd rqbknr1b/pp1ppp2/2p2n1p/6p1/8/3P1PPP/PPP1P3/RQBKNRNB w FAfa - perft 1 20 perft 2 560 perft 3 12275 @@ -7121,7 +7121,7 @@ perft 5 8687544 perft 6 277906201 id 791 -epd rbqkbnrn/p3pppp/1p6/3p4/P1p3P1/1P6/1QPPPP1P/RB1KBNRN w GAga - 0 9 +epd rbqkbnrn/p3pppp/1p6/3p4/P1p3P1/1P6/1QPPPP1P/RB1KBNRN w GAga - perft 1 30 perft 2 1155 perft 3 35865 @@ -7130,7 +7130,7 @@ perft 5 43092716 perft 6 1614019629 id 792 -epd rqkbb1rn/p1p1pppn/1p1p4/7p/4PP2/7P/PPPPB1P1/RQK1BNRN w GAga - 1 9 +epd rqkbb1rn/p1p1pppn/1p1p4/7p/4PP2/7P/PPPPB1P1/RQK1BNRN w GAga - perft 1 30 perft 2 701 perft 3 20804 @@ -7139,7 +7139,7 @@ perft 5 15450970 perft 6 401499189 id 793 -epd rqknbbrn/1p2pp1p/3p2p1/p1p5/P2P4/1P6/1KP1PPPP/RQ1NBBRN w ga - 0 9 +epd rqknbbrn/1p2pp1p/3p2p1/p1p5/P2P4/1P6/1KP1PPPP/RQ1NBBRN w ga - perft 1 28 perft 2 756 perft 3 21655 @@ -7148,7 +7148,7 @@ perft 5 17989811 perft 6 525585996 id 794 -epd rqknbrnb/1pp3pp/5p2/p2pp3/P7/3PPN2/1PP2PPP/RQKNBR1B w FAfa - 0 9 +epd rqknbrnb/1pp3pp/5p2/p2pp3/P7/3PPN2/1PP2PPP/RQKNBR1B w FAfa - perft 1 26 perft 2 731 perft 3 19509 @@ -7157,7 +7157,7 @@ perft 5 15209404 perft 6 439767476 id 795 -epd rbqkr1bn/p1pppp1p/1p1n4/6p1/7P/3P1PP1/PPP1P3/RBQKNRBN w FAa - 0 9 +epd rbqkr1bn/p1pppp1p/1p1n4/6p1/7P/3P1PP1/PPP1P3/RBQKNRBN w FAa - perft 1 27 perft 2 586 perft 3 16282 @@ -7166,7 +7166,7 @@ perft 5 10905865 perft 6 274364342 id 796 -epd rqk1nrb1/ppbp1ppp/4p1n1/2p5/7P/1PP5/P2PPPP1/RQKBNRBN w FAfa - 1 9 +epd rqk1nrb1/ppbp1ppp/4p1n1/2p5/7P/1PP5/P2PPPP1/RQKBNRBN w FAfa - perft 1 27 perft 2 749 perft 3 21480 @@ -7175,7 +7175,7 @@ perft 5 18084787 perft 6 520547029 id 797 -epd rqknrbbn/pp1p1ppp/4p3/2p5/3P2P1/7P/PPP1PP2/RQKNRBBN w EAa - 0 9 +epd rqknrbbn/pp1p1ppp/4p3/2p5/3P2P1/7P/PPP1PP2/RQKNRBBN w EAa - perft 1 20 perft 2 533 perft 3 11829 @@ -7184,7 +7184,7 @@ perft 5 8230417 perft 6 245871540 id 798 -epd rqknrnbb/pp1ppp1p/2p3p1/8/8/1P2P1NP/P1PP1PP1/RQKNR1BB w EAea - 0 9 +epd rqknrnbb/pp1ppp1p/2p3p1/8/8/1P2P1NP/P1PP1PP1/RQKNR1BB w EAea - perft 1 22 perft 2 633 perft 3 14480 @@ -7193,7 +7193,7 @@ perft 5 10827868 perft 6 343525739 id 799 -epd 1brkq1rn/2pppppp/1p2n3/p2bN3/8/7P/PPPPPPP1/BBRKQ1RN w GCgc - 2 9 +epd 1brkq1rn/2pppppp/1p2n3/p2bN3/8/7P/PPPPPPP1/BBRKQ1RN w GCgc - perft 1 27 perft 2 748 perft 3 20134 @@ -7202,7 +7202,7 @@ perft 5 16010135 perft 6 475206624 id 800 -epd brkbqnrn/2pp1ppp/8/1p2p3/Pp2N3/8/2PPPPPP/BRKBQNR1 w GBgb - 0 9 +epd brkbqnrn/2pp1ppp/8/1p2p3/Pp2N3/8/2PPPPPP/BRKBQNR1 w GBgb - perft 1 30 perft 2 827 perft 3 25308 @@ -7211,7 +7211,7 @@ perft 5 23746165 perft 6 751690068 id 801 -epd brk1nbrn/pp1ppppp/2p5/7P/5P2/q2P4/PPP1P1P1/BRKQNBRN w GBgb - 1 9 +epd brk1nbrn/pp1ppppp/2p5/7P/5P2/q2P4/PPP1P1P1/BRKQNBRN w GBgb - perft 1 15 perft 2 471 perft 3 8716 @@ -7220,7 +7220,7 @@ perft 5 5960901 perft 6 190316951 id 802 -epd brkqnrnb/1p1pp1p1/p4p2/2p4p/8/P2PP3/1PP1QPPP/BRK1NRNB w FBfb - 0 9 +epd brkqnrnb/1p1pp1p1/p4p2/2p4p/8/P2PP3/1PP1QPPP/BRK1NRNB w FBfb - perft 1 24 perft 2 479 perft 3 12584 @@ -7229,7 +7229,7 @@ perft 5 7830230 perft 6 190419716 id 803 -epd rbbkqnrn/2ppp2p/pp3p2/6p1/P6P/8/RPPPPPP1/1BBKQNRN w Gga - 0 9 +epd rbbkqnrn/2ppp2p/pp3p2/6p1/P6P/8/RPPPPPP1/1BBKQNRN w Gga - perft 1 21 perft 2 523 perft 3 12125 @@ -7238,7 +7238,7 @@ perft 5 8322614 perft 6 242240658 id 804 -epd rkbbqr1n/1ppppppn/7p/p7/4P3/2P2P2/PP1PB1PP/RKB1QNRN w GAa - 3 9 +epd rkbbqr1n/1ppppppn/7p/p7/4P3/2P2P2/PP1PB1PP/RKB1QNRN w GAa - perft 1 27 perft 2 563 perft 3 16026 @@ -7247,7 +7247,7 @@ perft 5 11105151 perft 6 283211800 id 805 -epd rkbqnbrn/ppppp3/8/5ppp/2P3P1/7P/PPQPPP2/RKB1NBRN w GAga - 0 9 +epd rkbqnbrn/ppppp3/8/5ppp/2P3P1/7P/PPQPPP2/RKB1NBRN w GAga - perft 1 28 perft 2 639 perft 3 19250 @@ -7256,7 +7256,7 @@ perft 5 14872172 perft 6 384663405 id 806 -epd rkb1nrnb/pppp1pp1/5q1p/8/P3p3/4R1P1/1PPPPP1P/1KBQNRNB w Ffa - 0 9 +epd rkb1nrnb/pppp1pp1/5q1p/8/P3p3/4R1P1/1PPPPP1P/1KBQNRNB w Ffa - perft 1 28 perft 2 873 perft 3 23690 @@ -7265,7 +7265,7 @@ perft 5 20209424 perft 6 625281937 id 807 -epd rbkqb1rn/1p1ppppp/4n3/p1p5/8/3PBP2/PPP1P1PP/RBKQ1NRN w GAga - 0 9 +epd rbkqb1rn/1p1ppppp/4n3/p1p5/8/3PBP2/PPP1P1PP/RBKQ1NRN w GAga - perft 1 26 perft 2 798 perft 3 21416 @@ -7274,7 +7274,7 @@ perft 5 18475618 perft 6 591681956 id 808 -epd rk1qbnrn/1p1ppppp/1b6/p1p5/P7/2P3NP/1P1PPPP1/RKQBB1RN w GAga - 0 9 +epd rk1qbnrn/1p1ppppp/1b6/p1p5/P7/2P3NP/1P1PPPP1/RKQBB1RN w GAga - perft 1 22 perft 2 506 perft 3 12313 @@ -7283,7 +7283,7 @@ perft 5 7891676 perft 6 205739580 id 809 -epd rk1nbbrn/ppp1ppp1/8/3p3p/1P1P2q1/5PB1/P1P1P1PP/RKQN1BRN w GAga - 1 9 +epd rk1nbbrn/ppp1ppp1/8/3p3p/1P1P2q1/5PB1/P1P1P1PP/RKQN1BRN w GAga - perft 1 31 perft 2 956 perft 3 29219 @@ -7292,7 +7292,7 @@ perft 5 27827461 perft 6 876341492 id 810 -epd rkqnbr1b/pp1pppp1/7p/2p2n2/P2P4/7N/RPP1PPPP/1KQNBR1B w Ffa - 0 9 +epd rkqnbr1b/pp1pppp1/7p/2p2n2/P2P4/7N/RPP1PPPP/1KQNBR1B w Ffa - perft 1 31 perft 2 750 perft 3 24267 @@ -7301,7 +7301,7 @@ perft 5 21639104 perft 6 617064197 id 811 -epd rbkq1rbn/2p1pppp/pp3n2/3p4/5P2/3N2N1/PPPPP1PP/RBKQR1B1 w Afa - 2 9 +epd rbkq1rbn/2p1pppp/pp3n2/3p4/5P2/3N2N1/PPPPP1PP/RBKQR1B1 w Afa - perft 1 26 perft 2 647 perft 3 18027 @@ -7310,7 +7310,7 @@ perft 5 13643783 perft 6 369702807 id 812 -epd rkqbr1bn/p2ppppp/1pp2n2/8/5P2/3P1N2/PPP1PRPP/RKQB2BN w Aa - 3 9 +epd rkqbr1bn/p2ppppp/1pp2n2/8/5P2/3P1N2/PPP1PRPP/RKQB2BN w Aa - perft 1 24 perft 2 574 perft 3 14593 @@ -7319,7 +7319,7 @@ perft 5 10066892 perft 6 271121237 id 813 -epd rk1qrbbn/p1ppp1pp/1p2n3/5p2/1P6/K3N3/P1PPPPPP/R1Q1RBBN w ea - 0 9 +epd rk1qrbbn/p1ppp1pp/1p2n3/5p2/1P6/K3N3/P1PPPPPP/R1Q1RBBN w ea - perft 1 25 perft 2 548 perft 3 14069 @@ -7328,7 +7328,7 @@ perft 5 9043111 perft 6 235545764 id 814 -epd rkqnrnbb/pp1pp3/2p5/5ppp/8/PP4NP/2PPPPP1/RKQNR1BB w EAea - 0 9 +epd rkqnrnbb/pp1pp3/2p5/5ppp/8/PP4NP/2PPPPP1/RKQNR1BB w EAea - perft 1 23 perft 2 727 perft 3 18228 @@ -7337,7 +7337,7 @@ perft 5 15078056 perft 6 471296844 id 815 -epd bbrknq1r/ppppppp1/8/7p/5n2/3P4/PPP1PNPP/BBKRNQR1 w c - 0 9 +epd bbrknq1r/ppppppp1/8/7p/5n2/3P4/PPP1PNPP/BBKRNQR1 w c - perft 1 21 perft 2 610 perft 3 13300 @@ -7346,7 +7346,7 @@ perft 5 9605845 perft 6 293532398 id 816 -epd brkbnqr1/2pppnpp/pp3p2/8/4PPPP/8/PPPP4/BRKBNQRN w GBgb - 1 9 +epd brkbnqr1/2pppnpp/pp3p2/8/4PPPP/8/PPPP4/BRKBNQRN w GBgb - perft 1 30 perft 2 757 perft 3 23908 @@ -7355,7 +7355,7 @@ perft 5 20360394 perft 6 548380577 id 817 -epd brk1qb1n/ppppppr1/2n3pp/8/2P3P1/2N5/PP1PPP1P/BR1KQBRN w b - 1 9 +epd brk1qb1n/ppppppr1/2n3pp/8/2P3P1/2N5/PP1PPP1P/BR1KQBRN w b - perft 1 26 perft 2 570 perft 3 15537 @@ -7364,7 +7364,7 @@ perft 5 10081351 perft 6 242864559 id 818 -epd brknq1nb/pp2prpp/8/2pP1p2/6P1/2N5/PPPP1P1P/BRK1QRNB w FBb - 1 9 +epd brknq1nb/pp2prpp/8/2pP1p2/6P1/2N5/PPPP1P1P/BRK1QRNB w FBb - perft 1 33 perft 2 830 perft 3 27897 @@ -7373,7 +7373,7 @@ perft 5 26262884 perft 6 765831403 id 819 -epd rbbk1qrn/ppp1p1pp/5p2/3p1n2/7N/P7/1PPPPPPP/RBB1KQRN w ga - 0 9 +epd rbbk1qrn/ppp1p1pp/5p2/3p1n2/7N/P7/1PPPPPPP/RBB1KQRN w ga - perft 1 21 perft 2 562 perft 3 13060 @@ -7382,7 +7382,7 @@ perft 5 9520963 perft 6 290579255 id 820 -epd rk1b1qrn/ppp1pppp/5n2/3pN3/P6P/7b/1PPPPPP1/RKBB1QRN w GAga - 4 9 +epd rk1b1qrn/ppp1pppp/5n2/3pN3/P6P/7b/1PPPPPP1/RKBB1QRN w GAga - perft 1 28 perft 2 677 perft 3 19235 @@ -7391,7 +7391,7 @@ perft 5 14354779 perft 6 383207197 id 821 -epd rkbnqbrn/pp1ppp1p/2p5/6p1/P7/4P3/KPPPQPPP/R1BN1BRN w - - 3 9 +epd rkbnqbrn/pp1ppp1p/2p5/6p1/P7/4P3/KPPPQPPP/R1BN1BRN w - - perft 1 28 perft 2 585 perft 3 17443 @@ -7400,7 +7400,7 @@ perft 5 12574541 perft 6 310495538 id 822 -epd rk1nqrnb/pbpppp2/1p4p1/7p/P7/5NP1/1PPPPPBP/RKBNQR2 w FAfa - 2 9 +epd rk1nqrnb/pbpppp2/1p4p1/7p/P7/5NP1/1PPPPPBP/RKBNQR2 w FAfa - perft 1 26 perft 2 774 perft 3 21626 @@ -7409,7 +7409,7 @@ perft 5 19093408 perft 6 576325868 id 823 -epd rbknb1rn/p1pp2pp/1p6/4pp2/1q3P1B/2N5/PPPPPNPP/RBK2QR1 w GAga - 2 9 +epd rbknb1rn/p1pp2pp/1p6/4pp2/1q3P1B/2N5/PPPPPNPP/RBK2QR1 w GAga - perft 1 31 perft 2 1206 perft 3 36940 @@ -7418,7 +7418,7 @@ perft 5 42849564 perft 6 1555711209 id 824 -epd rk1bbqrn/pp1pp1pp/3n4/5p2/3p4/1PP5/PK2PPPP/R1NBBQRN w ga - 0 9 +epd rk1bbqrn/pp1pp1pp/3n4/5p2/3p4/1PP5/PK2PPPP/R1NBBQRN w ga - perft 1 21 perft 2 629 perft 3 14059 @@ -7427,7 +7427,7 @@ perft 5 10587910 perft 6 332632033 id 825 -epd rknqbbr1/p1pp1pp1/1p4n1/4p2p/4P1P1/6RB/PPPP1P1P/RKNQB2N w Aga - 0 9 +epd rknqbbr1/p1pp1pp1/1p4n1/4p2p/4P1P1/6RB/PPPP1P1P/RKNQB2N w Aga - perft 1 27 perft 2 753 perft 3 20918 @@ -7436,7 +7436,7 @@ perft 5 17318772 perft 6 507563675 id 826 -epd rknqbr1b/pppp1ppp/4p2n/8/1P3P2/4P3/P1PPN1PP/RKNQBR1B w FAfa - 2 9 +epd rknqbr1b/pppp1ppp/4p2n/8/1P3P2/4P3/P1PPN1PP/RKNQBR1B w FAfa - perft 1 26 perft 2 623 perft 3 17177 @@ -7445,7 +7445,7 @@ perft 5 13389799 perft 6 383508368 id 827 -epd r2kqrbn/bppppppp/2n5/p4B2/5P2/2P5/PP1PP1PP/1RKNQRBN w F - 2 9 +epd r2kqrbn/bppppppp/2n5/p4B2/5P2/2P5/PP1PP1PP/1RKNQRBN w F - perft 1 39 perft 2 1026 perft 3 37800 @@ -7454,7 +7454,7 @@ perft 5 35946987 perft 6 992756232 id 828 -epd rk1bqrb1/ppppppp1/1n6/7p/2P2P1n/4P1Q1/PP1P2PP/RKNB1RBN w FAfa - 0 9 +epd rk1bqrb1/ppppppp1/1n6/7p/2P2P1n/4P1Q1/PP1P2PP/RKNB1RBN w FAfa - perft 1 35 perft 2 760 perft 3 25817 @@ -7463,7 +7463,7 @@ perft 5 21014787 perft 6 536852043 id 829 -epd rkq1rb1n/ppppp1pp/1n6/5p2/PPb2P2/8/1KPPP1PP/R1NQRBBN w ea - 1 9 +epd rkq1rb1n/ppppp1pp/1n6/5p2/PPb2P2/8/1KPPP1PP/R1NQRBBN w ea - perft 1 27 perft 2 754 perft 3 21009 @@ -7472,7 +7472,7 @@ perft 5 16461795 perft 6 448313956 id 830 -epd rknqr2b/pppnp1pp/3p4/3b1p2/8/1N1P2N1/PPP1PPPP/RKQ1R1BB w EAea - 1 9 +epd rknqr2b/pppnp1pp/3p4/3b1p2/8/1N1P2N1/PPP1PPPP/RKQ1R1BB w EAea - perft 1 27 perft 2 803 perft 3 23708 @@ -7481,7 +7481,7 @@ perft 5 21875031 perft 6 654754840 id 831 -epd bbrknrqn/ppppp1pB/8/2P2p1p/8/5N2/PP1PPPPP/B1RK1RQN w FCfc - 0 9 +epd bbrknrqn/ppppp1pB/8/2P2p1p/8/5N2/PP1PPPPP/B1RK1RQN w FCfc - perft 1 30 perft 2 799 perft 3 23923 @@ -7490,7 +7490,7 @@ perft 5 20532790 perft 6 603059376 id 832 -epd brkbnrq1/1pppp1p1/6np/p4p2/4P3/1PP5/P1KP1PPP/BR1BNRQN w fb - 1 9 +epd brkbnrq1/1pppp1p1/6np/p4p2/4P3/1PP5/P1KP1PPP/BR1BNRQN w fb - perft 1 27 perft 2 726 perft 3 19329 @@ -7499,7 +7499,7 @@ perft 5 15156662 perft 6 457601127 id 833 -epd brknrbq1/1p1p1ppp/p3p1n1/2p5/8/1P1BPP2/P1PP2PP/BRKNR1QN w EBeb - 0 9 +epd brknrbq1/1p1p1ppp/p3p1n1/2p5/8/1P1BPP2/P1PP2PP/BRKNR1QN w EBeb - perft 1 36 perft 2 786 perft 3 27868 @@ -7508,7 +7508,7 @@ perft 5 22852433 perft 6 577223409 id 834 -epd brknrqnb/p2ppp1p/2p5/1p6/3P2p1/P1P1N3/1P2PPPP/BRK1RQNB w EBeb - 0 9 +epd brknrqnb/p2ppp1p/2p5/1p6/3P2p1/P1P1N3/1P2PPPP/BRK1RQNB w EBeb - perft 1 23 perft 2 649 perft 3 15169 @@ -7517,7 +7517,7 @@ perft 5 10687843 perft 6 320881984 id 835 -epd rbbk1rqn/1ppppppp/3n4/p7/2P5/3N4/PP1PPPPP/RBB1KRQN w fa - 1 9 +epd rbbk1rqn/1ppppppp/3n4/p7/2P5/3N4/PP1PPPPP/RBB1KRQN w fa - perft 1 20 perft 2 478 perft 3 11094 @@ -7526,7 +7526,7 @@ perft 5 7094988 perft 6 185488058 id 836 -epd rkbbnrqn/p2p1ppp/1p2p3/8/P1p1P3/1BP5/1P1P1PPP/RKB1NRQN w FAfa - 0 9 +epd rkbbnrqn/p2p1ppp/1p2p3/8/P1p1P3/1BP5/1P1P1PPP/RKB1NRQN w FAfa - perft 1 22 perft 2 570 perft 3 13295 @@ -7535,7 +7535,7 @@ perft 5 8671852 perft 6 229898448 id 837 -epd rkb1rb1n/ppppppqp/8/2n3p1/2P1P1P1/8/PP1P1P1P/RKBNRBQN w EAea - 1 9 +epd rkb1rb1n/ppppppqp/8/2n3p1/2P1P1P1/8/PP1P1P1P/RKBNRBQN w EAea - perft 1 23 perft 2 663 perft 3 16212 @@ -7544,7 +7544,7 @@ perft 5 12900485 perft 6 404944553 id 838 -epd rkb1rqnb/pppp3p/2n3p1/4pp2/P2P3P/2P5/1P2PPP1/RKBNRQNB w EAea - 0 9 +epd rkb1rqnb/pppp3p/2n3p1/4pp2/P2P3P/2P5/1P2PPP1/RKBNRQNB w EAea - perft 1 25 perft 2 845 perft 3 22188 @@ -7553,7 +7553,7 @@ perft 5 20276176 perft 6 683290790 id 839 -epd rbk1brqn/ppp1pppp/8/3p4/7P/1P4P1/2PPPP2/RBKNBRQN w FAfa - 0 9 +epd rbk1brqn/ppp1pppp/8/3p4/7P/1P4P1/2PPPP2/RBKNBRQN w FAfa - perft 1 24 perft 2 526 perft 3 13862 @@ -7562,7 +7562,7 @@ perft 5 9054028 perft 6 222704171 id 840 -epd rknbbrqn/pp3pp1/4p3/2pp3p/2P5/8/PPBPPPPP/RKN1BRQN w FAfa - 0 9 +epd rknbbrqn/pp3pp1/4p3/2pp3p/2P5/8/PPBPPPPP/RKN1BRQN w FAfa - perft 1 26 perft 2 756 perft 3 19280 @@ -7571,7 +7571,7 @@ perft 5 14697705 perft 6 433719427 id 841 -epd 1knrbbqn/rp1p1ppp/p3p3/2p5/8/5P1P/PPPPP1P1/RKNRBBQN w DAd - 0 9 +epd 1knrbbqn/rp1p1ppp/p3p3/2p5/8/5P1P/PPPPP1P1/RKNRBBQN w DAd - perft 1 26 perft 2 539 perft 3 15194 @@ -7580,7 +7580,7 @@ perft 5 10223443 perft 6 248715580 id 842 -epd rknr1qnb/ppp1p1pp/3p2b1/8/4p3/1P3P1P/P1PP2P1/RKNRBQNB w DAda - 0 9 +epd rknr1qnb/ppp1p1pp/3p2b1/8/4p3/1P3P1P/P1PP2P1/RKNRBQNB w DAda - perft 1 25 perft 2 701 perft 3 18969 @@ -7589,7 +7589,7 @@ perft 5 16047041 perft 6 496340789 id 843 -epd rbk1r1bn/ppppp1pp/4n3/5p2/1P3P2/4N2P/PqPPP1P1/RBK1RQBN w EAea - 1 9 +epd rbk1r1bn/ppppp1pp/4n3/5p2/1P3P2/4N2P/PqPPP1P1/RBK1RQBN w EAea - perft 1 2 perft 2 60 perft 3 1319 @@ -7598,7 +7598,7 @@ perft 5 1017864 perft 6 33183408 id 844 -epd r1nbrqbn/k1ppp1pp/1p6/p4p2/2P5/6PQ/PP1PPP1P/RKNBR1BN w EA - 0 9 +epd r1nbrqbn/k1ppp1pp/1p6/p4p2/2P5/6PQ/PP1PPP1P/RKNBR1BN w EA - perft 1 27 perft 2 699 perft 3 20436 @@ -7607,7 +7607,7 @@ perft 5 17192121 perft 6 499247248 id 845 -epd rknrqbbn/1pp1pp2/p5p1/3p3p/6P1/PN5P/1PPPPP2/RK1RQBBN w DAda - 0 9 +epd rknrqbbn/1pp1pp2/p5p1/3p3p/6P1/PN5P/1PPPPP2/RK1RQBBN w DAda - perft 1 23 perft 2 611 perft 3 15515 @@ -7616,7 +7616,7 @@ perft 5 11917036 perft 6 352885930 id 846 -epd rknrqn1b/p1pp1ppb/8/1p2p1Qp/3P4/3N4/PPP1PPPP/RK1R1NBB w DAda - 0 9 +epd rknrqn1b/p1pp1ppb/8/1p2p1Qp/3P4/3N4/PPP1PPPP/RK1R1NBB w DAda - perft 1 45 perft 2 1170 perft 3 48283 @@ -7625,7 +7625,7 @@ perft 5 52213677 perft 6 1500007485 id 847 -epd bbkrnrnq/p2p1ppp/2p1p3/1p6/1P2Q3/6P1/P1PPPP1P/BBKRNRN1 w - - 0 9 +epd bbkrnrnq/p2p1ppp/2p1p3/1p6/1P2Q3/6P1/P1PPPP1P/BBKRNRN1 w - - perft 1 41 perft 2 1035 perft 3 39895 @@ -7634,7 +7634,7 @@ perft 5 38555608 perft 6 1037686769 id 848 -epd brkbnr2/1ppppp1p/7n/p5N1/P2q4/8/1PPPPPPP/BRKBNRQ1 w FBfb - 1 9 +epd brkbnr2/1ppppp1p/7n/p5N1/P2q4/8/1PPPPPPP/BRKBNRQ1 w FBfb - perft 1 22 perft 2 869 perft 3 19234 @@ -7643,7 +7643,7 @@ perft 5 16453359 perft 6 567287944 id 849 -epd brknrbnq/p1ppppp1/1p6/7p/2PP4/5P2/PPK1P1PP/BR1NRBNQ w eb - 1 9 +epd brknrbnq/p1ppppp1/1p6/7p/2PP4/5P2/PPK1P1PP/BR1NRBNQ w eb - perft 1 23 perft 2 641 perft 3 14748 @@ -7652,7 +7652,7 @@ perft 5 10192718 perft 6 302864305 id 850 -epd brk1r1qb/pp1ppnpp/2p2pn1/8/6N1/2N3P1/PPPPPP1P/BRK1R1QB w EBeb - 3 9 +epd brk1r1qb/pp1ppnpp/2p2pn1/8/6N1/2N3P1/PPPPPP1P/BRK1R1QB w EBeb - perft 1 32 perft 2 863 perft 3 28379 @@ -7661,7 +7661,7 @@ perft 5 25848794 perft 6 720443112 id 851 -epd rbbk1rnq/pppp1pp1/4p2p/8/3P2n1/4BN1P/PPP1PPP1/RB1K1RNQ w FAfa - 3 9 +epd rbbk1rnq/pppp1pp1/4p2p/8/3P2n1/4BN1P/PPP1PPP1/RB1K1RNQ w FAfa - perft 1 26 perft 2 628 perft 3 16151 @@ -7670,7 +7670,7 @@ perft 5 11237919 perft 6 300314373 id 852 -epd rkbbnr1q/p1pppppp/5n2/1p5B/PP6/4P3/2PP1PPP/RKB1NRNQ w FAfa - 0 9 +epd rkbbnr1q/p1pppppp/5n2/1p5B/PP6/4P3/2PP1PPP/RKB1NRNQ w FAfa - perft 1 30 perft 2 692 perft 3 21036 @@ -7679,7 +7679,7 @@ perft 5 16025428 perft 6 420887328 id 853 -epd rkb1rbnq/1pppp1pp/5p2/p7/5n1P/1PN3P1/P1PPPP2/RKB1RBNQ w EAea - 0 9 +epd rkb1rbnq/1pppp1pp/5p2/p7/5n1P/1PN3P1/P1PPPP2/RKB1RBNQ w EAea - perft 1 32 perft 2 825 perft 3 27130 @@ -7688,7 +7688,7 @@ perft 5 23593363 perft 6 622249676 id 854 -epd rkbnrnqb/1ppp1p1p/p5p1/4p3/4P3/2N2P2/PPPP2PP/RKBR1NQB w Aea - 0 9 +epd rkbnrnqb/1ppp1p1p/p5p1/4p3/4P3/2N2P2/PPPP2PP/RKBR1NQB w Aea - perft 1 24 perft 2 487 perft 3 13300 @@ -7697,7 +7697,7 @@ perft 5 8782713 perft 6 215787079 id 855 -epd rbknbr1q/pppp2pp/4p3/5p1n/1P2P2N/8/P1PP1PPP/RBKNBR1Q w FAfa - 0 9 +epd rbknbr1q/pppp2pp/4p3/5p1n/1P2P2N/8/P1PP1PPP/RBKNBR1Q w FAfa - perft 1 23 perft 2 571 perft 3 13799 @@ -7706,7 +7706,7 @@ perft 5 9224232 perft 6 257288920 id 856 -epd rknbb1nq/pppppr2/5pp1/7p/8/1N4P1/PPPPPP1P/RK1BBRNQ w FAa - 2 9 +epd rknbb1nq/pppppr2/5pp1/7p/8/1N4P1/PPPPPP1P/RK1BBRNQ w FAa - perft 1 26 perft 2 548 perft 3 15618 @@ -7715,7 +7715,7 @@ perft 5 10587626 perft 6 253006082 id 857 -epd rknr1bnq/p2pp1pp/1p3p2/2p4b/6PP/2P2N2/PP1PPP2/RKNRBB1Q w DAda - 1 9 +epd rknr1bnq/p2pp1pp/1p3p2/2p4b/6PP/2P2N2/PP1PPP2/RKNRBB1Q w DAda - perft 1 25 perft 2 502 perft 3 13150 @@ -7724,7 +7724,7 @@ perft 5 7824941 perft 6 175766730 id 858 -epd rknrb1qb/ppp1pppp/3p4/8/4P1nP/2P5/PPKP1PP1/R1NRBNQB w da - 1 9 +epd rknrb1qb/ppp1pppp/3p4/8/4P1nP/2P5/PPKP1PP1/R1NRBNQB w da - perft 1 23 perft 2 643 perft 3 14849 @@ -7733,7 +7733,7 @@ perft 5 10507328 perft 6 312096061 id 859 -epd rbk1rnbq/pppp1npp/4p3/5p2/4P1P1/7P/PPPP1P1N/RBKNR1BQ w EAea - 1 9 +epd rbk1rnbq/pppp1npp/4p3/5p2/4P1P1/7P/PPPP1P1N/RBKNR1BQ w EAea - perft 1 24 perft 2 591 perft 3 15178 @@ -7742,7 +7742,7 @@ perft 5 10251465 perft 6 263574861 id 860 -epd rknbrnb1/p1pppp1p/1p6/3N2p1/P3q1P1/8/1PPPPP1P/RKNBR1BQ w EAea - 1 9 +epd rknbrnb1/p1pppp1p/1p6/3N2p1/P3q1P1/8/1PPPPP1P/RKNBR1BQ w EAea - perft 1 28 perft 2 948 perft 3 27343 @@ -7751,7 +7751,7 @@ perft 5 26241141 perft 6 812343987 id 861 -epd rknrn1b1/ppppppqp/8/6p1/2P5/2P1BP2/PP2P1PP/RKNRNB1Q w DAda - 1 9 +epd rknrn1b1/ppppppqp/8/6p1/2P5/2P1BP2/PP2P1PP/RKNRNB1Q w DAda - perft 1 31 perft 2 807 perft 3 24360 @@ -7760,7 +7760,7 @@ perft 5 20455205 perft 6 588518645 id 862 -epd 1k1rnqbb/npppppp1/r7/p2B3p/5P2/1N4P1/PPPPP2P/RK1RNQB1 w DAd - 0 9 +epd 1k1rnqbb/npppppp1/r7/p2B3p/5P2/1N4P1/PPPPP2P/RK1RNQB1 w DAd - perft 1 40 perft 2 1122 perft 3 44297 @@ -7769,7 +7769,7 @@ perft 5 48711073 perft 6 1412437357 id 863 -epd bbqr1rkn/pp1ppppp/8/2p5/1P2P1n1/7N/P1PP1P1P/BBQRKR1N w FD - 0 9 +epd bbqr1rkn/pp1ppppp/8/2p5/1P2P1n1/7N/P1PP1P1P/BBQRKR1N w FD - perft 1 26 perft 2 841 perft 3 22986 @@ -7778,7 +7778,7 @@ perft 5 21328001 perft 6 705170410 id 864 -epd bqkr1rnn/1ppp1ppp/p4b2/4p3/P7/3PP2N/1PP2PPP/BQRBKR1N w FC - 3 9 +epd bqkr1rnn/1ppp1ppp/p4b2/4p3/P7/3PP2N/1PP2PPP/BQRBKR1N w FC - perft 1 24 perft 2 500 perft 3 12802 @@ -7787,7 +7787,7 @@ perft 5 7928916 perft 6 197806842 id 865 -epd bqrkrbnn/1pp1ppp1/8/p6p/3p4/P3P2P/QPPP1PP1/B1RKRBNN w ECec - 0 9 +epd bqrkrbnn/1pp1ppp1/8/p6p/3p4/P3P2P/QPPP1PP1/B1RKRBNN w ECec - perft 1 31 perft 2 592 perft 3 18585 @@ -7796,7 +7796,7 @@ perft 5 12607528 perft 6 298629240 id 866 -epd bqkrrnnb/2p1pppp/p7/1P1p4/8/2R3P1/PP1PPP1P/BQ1KRNNB w E - 0 9 +epd bqkrrnnb/2p1pppp/p7/1P1p4/8/2R3P1/PP1PPP1P/BQ1KRNNB w E - perft 1 42 perft 2 1124 perft 3 45187 @@ -7805,7 +7805,7 @@ perft 5 50052573 perft 6 1483524894 id 867 -epd qbbrkrn1/p1pppn1p/8/1p3Pp1/2P5/8/PP1PPP1P/QBBRKRNN w FDfd - 0 9 +epd qbbrkrn1/p1pppn1p/8/1p3Pp1/2P5/8/PP1PPP1P/QBBRKRNN w FDfd - perft 1 21 perft 2 577 perft 3 13244 @@ -7814,7 +7814,7 @@ perft 5 9683808 perft 6 300294295 id 868 -epd qrbbkrnn/pp1p2pp/4p3/5p2/2p2P1P/2P5/PP1PP1P1/QRBBKRNN w FBfb - 0 9 +epd qrbbkrnn/pp1p2pp/4p3/5p2/2p2P1P/2P5/PP1PP1P1/QRBBKRNN w FBfb - perft 1 21 perft 2 571 perft 3 12736 @@ -7823,7 +7823,7 @@ perft 5 8239872 perft 6 228837930 id 869 -epd qrbkrbn1/1pp1pppp/p2p4/8/5PPn/2P5/PP1PP3/QRBKRBNN w EBeb - 0 9 +epd qrbkrbn1/1pp1pppp/p2p4/8/5PPn/2P5/PP1PP3/QRBKRBNN w EBeb - perft 1 18 perft 2 466 perft 3 9443 @@ -7832,7 +7832,7 @@ perft 5 5679073 perft 6 162883949 id 870 -epd qrb1rnnb/pp1p1ppp/2pk4/4p3/1P2P3/1R6/P1PP1PPP/Q1BKRNNB w E - 4 9 +epd qrb1rnnb/pp1p1ppp/2pk4/4p3/1P2P3/1R6/P1PP1PPP/Q1BKRNNB w E - perft 1 37 perft 2 760 perft 3 26863 @@ -7841,7 +7841,7 @@ perft 5 19486022 perft 6 421740856 id 871 -epd qbrkbrn1/p1pppp1p/6n1/1p4p1/1P6/5P2/P1PPPBPP/QBRK1RNN w FCfc - 1 9 +epd qbrkbrn1/p1pppp1p/6n1/1p4p1/1P6/5P2/P1PPPBPP/QBRK1RNN w FCfc - perft 1 33 perft 2 824 perft 3 27385 @@ -7850,7 +7850,7 @@ perft 5 25176664 perft 6 734656217 id 872 -epd qrkbbr2/2pppppp/5nn1/pp1Q4/P7/3P4/1PP1PPPP/1RKBBRNN w FBfb - 0 9 +epd qrkbbr2/2pppppp/5nn1/pp1Q4/P7/3P4/1PP1PPPP/1RKBBRNN w FBfb - perft 1 42 perft 2 1147 perft 3 44012 @@ -7859,7 +7859,7 @@ perft 5 48216013 perft 6 1522548864 id 873 -epd qrkrbbnn/pp2pp2/2pp2pp/1B6/P7/4P3/1PPP1PPP/QRKRB1NN w DBdb - 0 9 +epd qrkrbbnn/pp2pp2/2pp2pp/1B6/P7/4P3/1PPP1PPP/QRKRB1NN w DBdb - perft 1 26 perft 2 464 perft 3 12653 @@ -7868,7 +7868,7 @@ perft 5 6928220 perft 6 142507795 id 874 -epd qrkrbnnb/p1pp1pp1/1p5p/4p3/1P6/6PN/PKPPPP1P/QR1RBN1B w db - 0 9 +epd qrkrbnnb/p1pp1pp1/1p5p/4p3/1P6/6PN/PKPPPP1P/QR1RBN1B w db - perft 1 29 perft 2 705 perft 3 20000 @@ -7877,7 +7877,7 @@ perft 5 15055365 perft 6 419552571 id 875 -epd qbrkr1bn/p1p1pp1p/1p1p2n1/6p1/3P1P2/4P3/PPP3PP/QBKRRNBN w ec - 2 9 +epd qbrkr1bn/p1p1pp1p/1p1p2n1/6p1/3P1P2/4P3/PPP3PP/QBKRRNBN w ec - perft 1 23 perft 2 613 perft 3 14835 @@ -7886,7 +7886,7 @@ perft 5 10747407 perft 6 323905533 id 876 -epd qrk1rnb1/p1pp1ppp/1p2Bbn1/8/4P3/6P1/PPPP1P1P/QRK1RNBN w EBeb - 1 9 +epd qrk1rnb1/p1pp1ppp/1p2Bbn1/8/4P3/6P1/PPPP1P1P/QRK1RNBN w EBeb - perft 1 28 perft 2 927 perft 3 24887 @@ -7895,7 +7895,7 @@ perft 5 23063284 perft 6 807913585 id 877 -epd 1qkrnbbn/1rpppppp/pp6/5N2/P4P2/8/1PPPP1PP/QRKRNBB1 w DBd - 3 9 +epd 1qkrnbbn/1rpppppp/pp6/5N2/P4P2/8/1PPPP1PP/QRKRNBB1 w DBd - perft 1 30 perft 2 542 perft 3 16646 @@ -7904,7 +7904,7 @@ perft 5 10976745 perft 6 251694423 id 878 -epd qrkr2bb/pppppppp/8/1n2n3/1N5P/1P6/P1PPPPP1/QRKR1NBB w DBdb - 1 9 +epd qrkr2bb/pppppppp/8/1n2n3/1N5P/1P6/P1PPPPP1/QRKR1NBB w DBdb - perft 1 28 perft 2 719 perft 3 21048 @@ -7913,7 +7913,7 @@ perft 5 17351761 perft 6 479400272 id 879 -epd bbrqkrnn/3ppppp/8/ppp5/6P1/4P2N/PPPPKP1P/BBRQ1R1N w fc - 0 9 +epd bbrqkrnn/3ppppp/8/ppp5/6P1/4P2N/PPPPKP1P/BBRQ1R1N w fc - perft 1 21 perft 2 704 perft 3 16119 @@ -7922,7 +7922,7 @@ perft 5 13676371 perft 6 470796854 id 880 -epd brqbkrnn/1pp2p1p/3pp1p1/p5N1/8/1P6/P1PPPPPP/BRQBK1RN w Bfb - 0 9 +epd brqbkrnn/1pp2p1p/3pp1p1/p5N1/8/1P6/P1PPPPPP/BRQBK1RN w Bfb - perft 1 34 perft 2 688 perft 3 22827 @@ -7931,7 +7931,7 @@ perft 5 16639723 perft 6 402140795 id 881 -epd br1krb1n/2qppppp/pp3n2/8/1P4P1/8/P1PPPP1P/1RQKRBNN w EBeb - 0 9 +epd br1krb1n/2qppppp/pp3n2/8/1P4P1/8/P1PPPP1P/1RQKRBNN w EBeb - perft 1 24 perft 2 945 perft 3 23943 @@ -7940,7 +7940,7 @@ perft 5 25019636 perft 6 959651619 id 882 -epd brqkr1nb/2ppp1pp/1p2np2/p7/2P1PN2/8/PP1P1PPP/BRQKRN1B w EBeb - 0 9 +epd brqkr1nb/2ppp1pp/1p2np2/p7/2P1PN2/8/PP1P1PPP/BRQKRN1B w EBeb - perft 1 28 perft 2 675 perft 3 19728 @@ -7949,7 +7949,7 @@ perft 5 15516491 perft 6 417396563 id 883 -epd rbbqkrnn/3pppp1/p7/1pp4p/2P1P2P/8/PP1P1PP1/RBBQKRNN w FAfa - 0 9 +epd rbbqkrnn/3pppp1/p7/1pp4p/2P1P2P/8/PP1P1PP1/RBBQKRNN w FAfa - perft 1 26 perft 2 671 perft 3 18164 @@ -7958,7 +7958,7 @@ perft 5 14072641 perft 6 404960259 id 884 -epd rqbbkr1n/pp1p1p1p/4pn2/2p3p1/4P1P1/3P3P/PPP2P2/RQBBKRNN w FAfa - 0 9 +epd rqbbkr1n/pp1p1p1p/4pn2/2p3p1/4P1P1/3P3P/PPP2P2/RQBBKRNN w FAfa - perft 1 22 perft 2 633 perft 3 14629 @@ -7967,7 +7967,7 @@ perft 5 10776416 perft 6 335689685 id 885 -epd rqbkrbnn/p1ppp3/1p3pp1/7p/3P4/P1P5/1PQ1PPPP/R1BKRBNN w EAea - 0 9 +epd rqbkrbnn/p1ppp3/1p3pp1/7p/3P4/P1P5/1PQ1PPPP/R1BKRBNN w EAea - perft 1 32 perft 2 607 perft 3 20339 @@ -7976,7 +7976,7 @@ perft 5 15586203 perft 6 383515709 id 886 -epd rqbkrnn1/pp2ppbp/3p4/2p3p1/2P5/1P3N1P/P2PPPP1/RQBKRN1B w EAea - 1 9 +epd rqbkrnn1/pp2ppbp/3p4/2p3p1/2P5/1P3N1P/P2PPPP1/RQBKRN1B w EAea - perft 1 29 perft 2 943 perft 3 28732 @@ -7985,7 +7985,7 @@ perft 5 28761841 perft 6 907579129 id 887 -epd rbqkb1nn/1ppppr1p/p5p1/5p2/1P6/2P4P/P1KPPPP1/RBQ1BRNN w a - 1 9 +epd rbqkb1nn/1ppppr1p/p5p1/5p2/1P6/2P4P/P1KPPPP1/RBQ1BRNN w a - perft 1 22 perft 2 441 perft 3 10403 @@ -7994,7 +7994,7 @@ perft 5 5784206 perft 6 140934555 id 888 -epd rqkb1rnn/1pp1pp1p/p5p1/1b1p4/3P4/P5P1/RPP1PP1P/1QKBBRNN w Ffa - 1 9 +epd rqkb1rnn/1pp1pp1p/p5p1/1b1p4/3P4/P5P1/RPP1PP1P/1QKBBRNN w Ffa - perft 1 21 perft 2 505 perft 3 11592 @@ -8003,7 +8003,7 @@ perft 5 7147063 perft 6 188559137 id 889 -epd rq1rbbnn/pkp1ppp1/3p3p/1p2N1P1/8/8/PPPPPP1P/RQKRBB1N w DA - 0 9 +epd rq1rbbnn/pkp1ppp1/3p3p/1p2N1P1/8/8/PPPPPP1P/RQKRBB1N w DA - perft 1 27 perft 2 608 perft 3 16419 @@ -8012,7 +8012,7 @@ perft 5 10808908 perft 6 268393274 id 890 -epd rqkrb2b/p2ppppp/2p3nn/1p6/5P2/PP1P4/2P1P1PP/RQKRBNNB w DAda - 1 9 +epd rqkrb2b/p2ppppp/2p3nn/1p6/5P2/PP1P4/2P1P1PP/RQKRBNNB w DAda - perft 1 30 perft 2 749 perft 3 21563 @@ -8021,7 +8021,7 @@ perft 5 16916813 perft 6 485406712 id 891 -epd rbqkr1bn/pp1ppp2/2p1n2p/6p1/8/4BPNP/PPPPP1P1/RBQKRN2 w EAea - 0 9 +epd rbqkr1bn/pp1ppp2/2p1n2p/6p1/8/4BPNP/PPPPP1P1/RBQKRN2 w EAea - perft 1 23 perft 2 600 perft 3 15082 @@ -8030,7 +8030,7 @@ perft 5 11041820 perft 6 314327867 id 892 -epd rqkbrnb1/2ppp1pp/pp3pn1/8/5P2/B2P4/PPP1P1PP/RQKBRN1N w EAea - 2 9 +epd rqkbrnb1/2ppp1pp/pp3pn1/8/5P2/B2P4/PPP1P1PP/RQKBRN1N w EAea - perft 1 22 perft 2 569 perft 3 13541 @@ -8039,7 +8039,7 @@ perft 5 9395816 perft 6 269460607 id 893 -epd rqkrnbb1/p1p1pppp/1p4n1/3p4/7P/P3P3/1PPPBPP1/RQKRN1BN w DAda - 0 9 +epd rqkrnbb1/p1p1pppp/1p4n1/3p4/7P/P3P3/1PPPBPP1/RQKRN1BN w DAda - perft 1 27 perft 2 579 perft 3 15565 @@ -8048,7 +8048,7 @@ perft 5 10238486 perft 6 266047417 id 894 -epd rqkrn1bb/p1ppp1pp/4n3/1p6/6p1/4N3/PPPPPPPP/RQKR2BB w DAda - 0 9 +epd rqkrn1bb/p1ppp1pp/4n3/1p6/6p1/4N3/PPPPPPPP/RQKR2BB w DAda - perft 1 20 perft 2 462 perft 3 10234 @@ -8057,7 +8057,7 @@ perft 5 6563859 perft 6 193376359 id 895 -epd bbrkqr2/pppp1ppp/6nn/8/2P1p3/3PP2N/PP3PPP/BBRKQR1N w FCfc - 0 9 +epd bbrkqr2/pppp1ppp/6nn/8/2P1p3/3PP2N/PP3PPP/BBRKQR1N w FCfc - perft 1 28 perft 2 724 perft 3 21688 @@ -8066,7 +8066,7 @@ perft 5 19318355 perft 6 593204629 id 896 -epd brk1qrnn/1pppbppp/4p3/8/1p6/P1P4P/3PPPP1/BRKBQRNN w FBfb - 1 9 +epd brk1qrnn/1pppbppp/4p3/8/1p6/P1P4P/3PPPP1/BRKBQRNN w FBfb - perft 1 24 perft 2 662 perft 3 16920 @@ -8075,7 +8075,7 @@ perft 5 12610387 perft 6 355969349 id 897 -epd 1r1qrbnn/p1pkpppp/1p1p4/8/3P1PP1/P4b2/1PP1P2P/BRKQRBNN w EB - 1 9 +epd 1r1qrbnn/p1pkpppp/1p1p4/8/3P1PP1/P4b2/1PP1P2P/BRKQRBNN w EB - perft 1 22 perft 2 696 perft 3 17021 @@ -8084,7 +8084,7 @@ perft 5 13697382 perft 6 401903030 id 898 -epd 1rkqrnnb/p1p1p1pp/1p1p4/3b1p1N/4P3/5N2/PPPP1PPP/BRKQR2B w EBeb - 1 9 +epd 1rkqrnnb/p1p1p1pp/1p1p4/3b1p1N/4P3/5N2/PPPP1PPP/BRKQR2B w EBeb - perft 1 29 perft 2 887 perft 3 27035 @@ -8093,7 +8093,7 @@ perft 5 26051242 perft 6 791718847 id 899 -epd rbbkq1rn/pppppppp/7n/8/P7/3P3P/1PPKPPP1/RBB1QRNN w a - 3 9 +epd rbbkq1rn/pppppppp/7n/8/P7/3P3P/1PPKPPP1/RBB1QRNN w a - perft 1 22 perft 2 417 perft 3 9900 @@ -8102,7 +8102,7 @@ perft 5 5505063 perft 6 134818483 id 900 -epd rkbbqr1n/1p1pppp1/2p2n2/p4NBp/8/3P4/PPP1PPPP/RK1BQRN1 w FAfa - 0 9 +epd rkbbqr1n/1p1pppp1/2p2n2/p4NBp/8/3P4/PPP1PPPP/RK1BQRN1 w FAfa - perft 1 37 perft 2 832 perft 3 30533 @@ -8111,7 +8111,7 @@ perft 5 26676373 perft 6 673756141 id 901 -epd rkbqrb1n/3pBppp/ppp2n2/8/8/P2P4/1PP1PPPP/RK1QRBNN w EAea - 0 9 +epd rkbqrb1n/3pBppp/ppp2n2/8/8/P2P4/1PP1PPPP/RK1QRBNN w EAea - perft 1 28 perft 2 685 perft 3 19718 @@ -8120,7 +8120,7 @@ perft 5 16033316 perft 6 482288814 id 902 -epd rkb1rn1b/ppppqppp/4p3/8/1P2n1P1/5Q2/P1PP1P1P/RKB1RNNB w EAea - 2 9 +epd rkb1rn1b/ppppqppp/4p3/8/1P2n1P1/5Q2/P1PP1P1P/RKB1RNNB w EAea - perft 1 37 perft 2 1158 perft 3 40114 @@ -8129,7 +8129,7 @@ perft 5 44672979 perft 6 1389312729 id 903 -epd r1kqbrnn/pp1pp1p1/7p/2P2p2/5b2/3P4/P1P1P1PP/RBKQBRNN w FAfa - 0 9 +epd r1kqbrnn/pp1pp1p1/7p/2P2p2/5b2/3P4/P1P1P1PP/RBKQBRNN w FAfa - perft 1 5 perft 2 161 perft 3 4745 @@ -8138,7 +8138,7 @@ perft 5 4734999 perft 6 157499039 id 904 -epd rkqbbr1n/ppp1ppp1/8/Q2p3p/4n3/3P1P2/PPP1P1PP/RK1BBRNN w FAfa - 2 9 +epd rkqbbr1n/ppp1ppp1/8/Q2p3p/4n3/3P1P2/PPP1P1PP/RK1BBRNN w FAfa - perft 1 38 perft 2 1144 perft 3 40433 @@ -8147,7 +8147,7 @@ perft 5 43832975 perft 6 1366087771 id 905 -epd rkqrbbn1/p1ppppp1/Bp5p/8/P6n/2P1P3/1P1P1PPP/RKQRB1NN w DAda - 0 9 +epd rkqrbbn1/p1ppppp1/Bp5p/8/P6n/2P1P3/1P1P1PPP/RKQRB1NN w DAda - perft 1 28 perft 2 551 perft 3 15488 @@ -8156,7 +8156,7 @@ perft 5 9944107 perft 6 251179183 id 906 -epd rkqrb1nb/1ppp1ppp/p7/4p3/5n2/3P2N1/PPPQPPPP/RK1RB1NB w DAda - 0 9 +epd rkqrb1nb/1ppp1ppp/p7/4p3/5n2/3P2N1/PPPQPPPP/RK1RB1NB w DAda - perft 1 26 perft 2 690 perft 3 19877 @@ -8165,7 +8165,7 @@ perft 5 15965907 perft 6 418191735 id 907 -epd rbkqrnbn/pppp1p2/4p1p1/7p/7P/P2P4/BPP1PPP1/R1KQRNBN w EAea - 0 9 +epd rbkqrnbn/pppp1p2/4p1p1/7p/7P/P2P4/BPP1PPP1/R1KQRNBN w EAea - perft 1 27 perft 2 515 perft 3 13992 @@ -8174,7 +8174,7 @@ perft 5 8792550 perft 6 218658292 id 908 -epd rkqbrnbn/pp1ppp2/8/2p3p1/P1P4p/5P2/1PKPP1PP/R1QBRNBN w ea - 0 9 +epd rkqbrnbn/pp1ppp2/8/2p3p1/P1P4p/5P2/1PKPP1PP/R1QBRNBN w ea - perft 1 27 perft 2 627 perft 3 16843 @@ -8183,7 +8183,7 @@ perft 5 11978698 perft 6 328434174 id 909 -epd rkqrnbbn/1p2pp1p/3p2p1/p1p5/P5PP/3N4/1PPPPP2/RKQR1BBN w DAda - 0 9 +epd rkqrnbbn/1p2pp1p/3p2p1/p1p5/P5PP/3N4/1PPPPP2/RKQR1BBN w DAda - perft 1 23 perft 2 624 perft 3 15512 @@ -8192,7 +8192,7 @@ perft 5 11960861 perft 6 367311176 id 910 -epd rk2rnbb/ppqppppp/2pn4/8/1P3P2/6P1/P1PPP1NP/RKQR1NBB w DAa - 1 9 +epd rk2rnbb/ppqppppp/2pn4/8/1P3P2/6P1/P1PPP1NP/RKQR1NBB w DAa - perft 1 27 perft 2 727 perft 3 20206 @@ -8201,7 +8201,7 @@ perft 5 16633696 perft 6 505212747 id 911 -epd b1krrqnn/pp1ppp1p/2p3p1/8/P3Pb1P/1P6/2PP1PP1/BBRKRQNN w EC - 0 9 +epd b1krrqnn/pp1ppp1p/2p3p1/8/P3Pb1P/1P6/2PP1PP1/BBRKRQNN w EC - perft 1 32 perft 2 943 perft 3 30759 @@ -8210,7 +8210,7 @@ perft 5 28672582 perft 6 800922511 id 912 -epd 1rkbrqnn/p1pp1ppp/1p6/8/P2Pp3/8/1PPKPPQP/BR1BR1NN w eb - 0 9 +epd 1rkbrqnn/p1pp1ppp/1p6/8/P2Pp3/8/1PPKPPQP/BR1BR1NN w eb - perft 1 28 perft 2 916 perft 3 24892 @@ -8219,7 +8219,7 @@ perft 5 22840279 perft 6 759318058 id 913 -epd brkrqb1n/1pppp1pp/p7/3n1p2/P5P1/3PP3/1PP2P1P/BRKRQBNN w DBdb - 0 9 +epd brkrqb1n/1pppp1pp/p7/3n1p2/P5P1/3PP3/1PP2P1P/BRKRQBNN w DBdb - perft 1 27 perft 2 669 perft 3 18682 @@ -8228,7 +8228,7 @@ perft 5 13956472 perft 6 380267099 id 914 -epd brkrqnnb/3pppp1/1p6/p1p4p/2P3P1/6N1/PP1PPP1P/BRKRQ1NB w DBdb - 0 9 +epd brkrqnnb/3pppp1/1p6/p1p4p/2P3P1/6N1/PP1PPP1P/BRKRQ1NB w DBdb - perft 1 29 perft 2 699 perft 3 20042 @@ -8237,7 +8237,7 @@ perft 5 15093909 perft 6 406594531 id 915 -epd r1bkrq1n/pp2pppp/3b1n2/2pp2B1/6P1/3P1P2/PPP1P2P/RB1KRQNN w EAea - 2 9 +epd r1bkrq1n/pp2pppp/3b1n2/2pp2B1/6P1/3P1P2/PPP1P2P/RB1KRQNN w EAea - perft 1 27 perft 2 835 perft 3 22848 @@ -8246,7 +8246,7 @@ perft 5 19867800 perft 6 631209313 id 916 -epd rk1brq1n/p1p1pppp/3p1n2/1p3b2/4P3/2NQ4/PPPP1PPP/RKBBR2N w EAea - 4 9 +epd rk1brq1n/p1p1pppp/3p1n2/1p3b2/4P3/2NQ4/PPPP1PPP/RKBBR2N w EAea - perft 1 36 perft 2 1004 perft 3 35774 @@ -8255,7 +8255,7 @@ perft 5 35143142 perft 6 966310885 id 917 -epd rkbrqbnn/1p2ppp1/B1p5/p2p3p/4P2P/8/PPPP1PP1/RKBRQ1NN w DAda - 0 9 +epd rkbrqbnn/1p2ppp1/B1p5/p2p3p/4P2P/8/PPPP1PP1/RKBRQ1NN w DAda - perft 1 27 perft 2 748 perft 3 21005 @@ -8264,7 +8264,7 @@ perft 5 17597073 perft 6 515304215 id 918 -epd rkbrqn1b/pp1pp1pp/2p2p2/5n2/8/2P2P2/PP1PP1PP/RKBRQ1NB w DAda - 0 9 +epd rkbrqn1b/pp1pp1pp/2p2p2/5n2/8/2P2P2/PP1PP1PP/RKBRQ1NB w DAda - perft 1 20 perft 2 479 perft 3 10485 @@ -8273,7 +8273,7 @@ perft 5 6253775 perft 6 167767913 id 919 -epd rbkrbnn1/ppppp1pp/5q2/5p2/5P2/P3P2N/1PPP2PP/RBKRBQ1N w DAda - 3 9 +epd rbkrbnn1/ppppp1pp/5q2/5p2/5P2/P3P2N/1PPP2PP/RBKRBQ1N w DAda - perft 1 28 perft 2 947 perft 3 26900 @@ -8282,7 +8282,7 @@ perft 5 26007841 perft 6 838704143 id 920 -epd rkr1bqnn/1ppp1p1p/p5p1/4p3/3PP2b/2P2P2/PP4PP/RKRBBQNN w CAca - 0 9 +epd rkr1bqnn/1ppp1p1p/p5p1/4p3/3PP2b/2P2P2/PP4PP/RKRBBQNN w CAca - perft 1 31 perft 2 1004 perft 3 32006 @@ -8291,7 +8291,7 @@ perft 5 32688124 perft 6 1024529879 id 921 -epd rkrqbbnn/pppp3p/8/4ppp1/1PP4P/8/P2PPPP1/RKRQBBNN w CAca - 0 9 +epd rkrqbbnn/pppp3p/8/4ppp1/1PP4P/8/P2PPPP1/RKRQBBNN w CAca - perft 1 24 perft 2 717 perft 3 18834 @@ -8300,7 +8300,7 @@ perft 5 15844525 perft 6 484884485 id 922 -epd rkrqbn1b/pppp2pp/8/4pp2/1P1P2n1/5N2/P1P1PP1P/RKRQBN1B w CAca - 0 9 +epd rkrqbn1b/pppp2pp/8/4pp2/1P1P2n1/5N2/P1P1PP1P/RKRQBN1B w CAca - perft 1 25 perft 2 718 perft 3 19654 @@ -8309,7 +8309,7 @@ perft 5 17257753 perft 6 537354146 id 923 -epd rbkrqnbn/p1p1ppp1/1p1p4/8/3PP2p/2PB4/PP3PPP/R1KRQNBN w DAda - 0 9 +epd rbkrqnbn/p1p1ppp1/1p1p4/8/3PP2p/2PB4/PP3PPP/R1KRQNBN w DAda - perft 1 30 perft 2 754 perft 3 23298 @@ -8318,7 +8318,7 @@ perft 5 19338246 perft 6 532603566 id 924 -epd 1krbqnbn/1p2pppp/r1pp4/p7/8/1P1P2PP/P1P1PP2/RKRBQNBN w CAc - 0 9 +epd 1krbqnbn/1p2pppp/r1pp4/p7/8/1P1P2PP/P1P1PP2/RKRBQNBN w CAc - perft 1 21 perft 2 566 perft 3 13519 @@ -8327,7 +8327,7 @@ perft 5 9700847 perft 6 279864836 id 925 -epd rkrq1b2/pppppppb/3n2np/2N5/4P3/7P/PPPP1PP1/RKRQ1BBN w CAca - 1 9 +epd rkrq1b2/pppppppb/3n2np/2N5/4P3/7P/PPPP1PP1/RKRQ1BBN w CAca - perft 1 33 perft 2 654 perft 3 21708 @@ -8336,7 +8336,7 @@ perft 5 15990307 perft 6 382218272 id 926 -epd rkr1nnbb/ppp2p1p/3p1qp1/4p3/P5P1/3PN3/1PP1PP1P/RKRQN1BB w CAca - 1 9 +epd rkr1nnbb/ppp2p1p/3p1qp1/4p3/P5P1/3PN3/1PP1PP1P/RKRQN1BB w CAca - perft 1 28 perft 2 715 perft 3 20361 @@ -8345,7 +8345,7 @@ perft 5 16303092 perft 6 468666425 id 927 -epd bbrkrnqn/1p1ppppp/8/8/p2pP3/PP6/2P2PPP/BBRKRNQN w ECec - 0 9 +epd bbrkrnqn/1p1ppppp/8/8/p2pP3/PP6/2P2PPP/BBRKRNQN w ECec - perft 1 24 perft 2 757 perft 3 19067 @@ -8354,7 +8354,7 @@ perft 5 15957628 perft 6 509307623 id 928 -epd brkbrnqn/ppp2p2/4p3/P2p2pp/6P1/5P2/1PPPP2P/BRKBRNQN w EBeb - 0 9 +epd brkbrnqn/ppp2p2/4p3/P2p2pp/6P1/5P2/1PPPP2P/BRKBRNQN w EBeb - perft 1 25 perft 2 548 perft 3 14563 @@ -8363,7 +8363,7 @@ perft 5 9688526 perft 6 247750144 id 929 -epd brkr1bqn/1pppppp1/3n3p/1p6/P7/4P1P1/1PPP1P1P/BRKRN1QN w DBdb - 0 9 +epd brkr1bqn/1pppppp1/3n3p/1p6/P7/4P1P1/1PPP1P1P/BRKRN1QN w DBdb - perft 1 19 perft 2 359 perft 3 7430 @@ -8372,7 +8372,7 @@ perft 5 3521652 perft 6 81787718 id 930 -epd brkr1qnb/pppp2pp/2B1p3/5p2/2n5/6PP/PPPPPPN1/BRKR1QN1 w DBdb - 1 9 +epd brkr1qnb/pppp2pp/2B1p3/5p2/2n5/6PP/PPPPPPN1/BRKR1QN1 w DBdb - perft 1 27 perft 2 854 perft 3 23303 @@ -8381,7 +8381,7 @@ perft 5 20558538 perft 6 667089231 id 931 -epd rbbkrnqn/p1p1p1pp/8/1p1p4/1P1Pp3/6N1/P1P2PPP/RBBKRNQ1 w EAea - 0 9 +epd rbbkrnqn/p1p1p1pp/8/1p1p4/1P1Pp3/6N1/P1P2PPP/RBBKRNQ1 w EAea - perft 1 28 perft 2 723 perft 3 19844 @@ -8390,7 +8390,7 @@ perft 5 14621108 perft 6 397454100 id 932 -epd rkbbrn1n/pppppp2/5q1p/6p1/3P3P/4P3/PPP2PP1/RKBBRNQN w EAea - 1 9 +epd rkbbrn1n/pppppp2/5q1p/6p1/3P3P/4P3/PPP2PP1/RKBBRNQN w EAea - perft 1 25 perft 2 741 perft 3 19224 @@ -8399,7 +8399,7 @@ perft 5 15605840 perft 6 485037906 id 933 -epd rkbr1bq1/ppnppppp/6n1/2p5/2P1N2P/8/PP1PPPP1/RKBRNBQ1 w DAda - 3 9 +epd rkbr1bq1/ppnppppp/6n1/2p5/2P1N2P/8/PP1PPPP1/RKBRNBQ1 w DAda - perft 1 24 perft 2 547 perft 3 14359 @@ -8408,7 +8408,7 @@ perft 5 9410221 perft 6 234041078 id 934 -epd 1kbrnqnb/r1ppppp1/8/pp5p/8/1P1NP3/P1PP1PPP/RKB1RQNB w Ad - 2 9 +epd 1kbrnqnb/r1ppppp1/8/pp5p/8/1P1NP3/P1PP1PPP/RKB1RQNB w Ad - perft 1 26 perft 2 618 perft 3 17305 @@ -8417,7 +8417,7 @@ perft 5 13112297 perft 6 357030697 id 935 -epd rbkrb1qn/1pp1ppp1/3pn2p/pP6/8/4N1P1/P1PPPP1P/RBKRB1QN w DAda - 0 9 +epd rbkrb1qn/1pp1ppp1/3pn2p/pP6/8/4N1P1/P1PPPP1P/RBKRB1QN w DAda - perft 1 21 perft 2 544 perft 3 12492 @@ -8426,7 +8426,7 @@ perft 5 8381483 perft 6 236013157 id 936 -epd rkrbbnqn/ppppp3/5p2/6pp/5PBP/4P3/PPPP2P1/RKR1BNQN w CAca - 0 9 +epd rkrbbnqn/ppppp3/5p2/6pp/5PBP/4P3/PPPP2P1/RKR1BNQN w CAca - perft 1 30 perft 2 891 perft 3 25435 @@ -8435,7 +8435,7 @@ perft 5 21894752 perft 6 669256602 id 937 -epd rkr1bb1n/ppppp1pp/5p2/4n3/3QP3/5P2/RPPP2PP/1KRNBB1N w Cca - 1 9 +epd rkr1bb1n/ppppp1pp/5p2/4n3/3QP3/5P2/RPPP2PP/1KRNBB1N w Cca - perft 1 45 perft 2 1172 perft 3 51766 @@ -8444,7 +8444,7 @@ perft 5 57856784 perft 6 1501852662 id 938 -epd rkr1bqnb/pp1ppppp/8/2pN4/1P6/5N2/P1PPnPPP/RKR1BQ1B w CAca - 0 9 +epd rkr1bqnb/pp1ppppp/8/2pN4/1P6/5N2/P1PPnPPP/RKR1BQ1B w CAca - perft 1 28 perft 2 730 perft 3 20511 @@ -8453,7 +8453,7 @@ perft 5 16323242 perft 6 463032124 id 939 -epd rbkrnqb1/2ppppp1/p5np/1p6/8/3N4/PPPPPPPP/RBKRQNB1 w DAda - 2 9 +epd rbkrnqb1/2ppppp1/p5np/1p6/8/3N4/PPPPPPPP/RBKRQNB1 w DAda - perft 1 20 perft 2 417 perft 3 9159 @@ -8462,7 +8462,7 @@ perft 5 5180716 perft 6 133936564 id 940 -epd rkrbnqb1/p1pppnpp/5p2/1p6/2P5/1P1P1N2/P3PPPP/RKRB1QBN w CAca - 0 9 +epd rkrbnqb1/p1pppnpp/5p2/1p6/2P5/1P1P1N2/P3PPPP/RKRB1QBN w CAca - perft 1 25 perft 2 546 perft 3 14039 @@ -8471,7 +8471,7 @@ perft 5 8813781 perft 6 222026485 id 941 -epd rkr1qbbn/ppppppp1/4n3/7p/8/P7/KPPPPPPP/R1RNQBBN w ca - 0 9 +epd rkr1qbbn/ppppppp1/4n3/7p/8/P7/KPPPPPPP/R1RNQBBN w ca - perft 1 22 perft 2 484 perft 3 11458 @@ -8480,7 +8480,7 @@ perft 5 6633319 perft 6 163291279 id 942 -epd rkrnqnb1/1ppppp2/p5p1/7p/8/P1bPP3/1PP1QPPP/RKRN1NBB w CAca - 0 9 +epd rkrnqnb1/1ppppp2/p5p1/7p/8/P1bPP3/1PP1QPPP/RKRN1NBB w CAca - perft 1 22 perft 2 636 perft 3 15526 @@ -8489,7 +8489,7 @@ perft 5 11614241 perft 6 331083405 id 943 -epd b2krn1q/p1rppppp/1Q3n2/2p1b3/1P4P1/8/P1PPPP1P/BBRKRNN1 w ECe - 3 9 +epd b2krn1q/p1rppppp/1Q3n2/2p1b3/1P4P1/8/P1PPPP1P/BBRKRNN1 w ECe - perft 1 36 perft 2 1192 perft 3 42945 @@ -8498,7 +8498,7 @@ perft 5 50382104 perft 6 1650202838 id 944 -epd brkbrnn1/pp1pppp1/7q/2p5/6Pp/4P1NP/PPPP1P2/BRKBR1NQ w EBeb - 2 9 +epd brkbrnn1/pp1pppp1/7q/2p5/6Pp/4P1NP/PPPP1P2/BRKBR1NQ w EBeb - perft 1 30 perft 2 978 perft 3 29593 @@ -8507,7 +8507,7 @@ perft 5 29205057 perft 6 936568065 id 945 -epd brkrnb1q/pp1p1ppp/2p1p3/5n2/1P6/5N1N/P1PPPPPP/BRKR1B1Q w DBdb - 1 9 +epd brkrnb1q/pp1p1ppp/2p1p3/5n2/1P6/5N1N/P1PPPPPP/BRKR1B1Q w DBdb - perft 1 31 perft 2 897 perft 3 27830 @@ -8516,7 +8516,7 @@ perft 5 25423729 perft 6 755334868 id 946 -epd brkr1nqb/pp1p1pp1/2pn3p/P3p3/4P3/6P1/1PPP1P1P/BRKRNNQB w DBdb - 0 9 +epd brkr1nqb/pp1p1pp1/2pn3p/P3p3/4P3/6P1/1PPP1P1P/BRKRNNQB w DBdb - perft 1 19 perft 2 382 perft 3 8052 @@ -8525,7 +8525,7 @@ perft 5 4232274 perft 6 103537333 id 947 -epd r1bkrn1q/ppbppppp/5n2/2p5/3P4/P6N/1PP1PPPP/RBBKRNQ1 w EAea - 3 9 +epd r1bkrn1q/ppbppppp/5n2/2p5/3P4/P6N/1PP1PPPP/RBBKRNQ1 w EAea - perft 1 27 perft 2 822 perft 3 22551 @@ -8534,7 +8534,7 @@ perft 5 19115128 perft 6 578210135 id 948 -epd rkbbrnnq/pp2pppp/8/2pp4/P1P5/1P3P2/3PP1PP/RKBBRNNQ w EAea - 1 9 +epd rkbbrnnq/pp2pppp/8/2pp4/P1P5/1P3P2/3PP1PP/RKBBRNNQ w EAea - perft 1 23 perft 2 643 perft 3 15410 @@ -8543,7 +8543,7 @@ perft 5 11170489 perft 6 329615708 id 949 -epd rkbr1b1q/p1pppppp/1p1n4/7n/5QP1/3N4/PPPPPP1P/RKBR1BN1 w DAda - 4 9 +epd rkbr1b1q/p1pppppp/1p1n4/7n/5QP1/3N4/PPPPPP1P/RKBR1BN1 w DAda - perft 1 37 perft 2 943 perft 3 34382 @@ -8552,7 +8552,7 @@ perft 5 31568111 perft 6 842265141 id 950 -epd rkbr1nqb/pppp2np/8/4ppp1/1P6/6N1/P1PPPPPP/RKBRN1QB w DAda - 1 9 +epd rkbr1nqb/pppp2np/8/4ppp1/1P6/6N1/P1PPPPPP/RKBRN1QB w DAda - perft 1 23 perft 2 574 perft 3 13260 @@ -8561,7 +8561,7 @@ perft 5 9020291 perft 6 261247606 id 951 -epd rbkr1nnq/p1p1pp1p/1p4p1/3p4/b3P3/4N3/PPPPNPPP/RBKRB1Q1 w DAda - 0 9 +epd rbkr1nnq/p1p1pp1p/1p4p1/3p4/b3P3/4N3/PPPPNPPP/RBKRB1Q1 w DAda - perft 1 26 perft 2 900 perft 3 23414 @@ -8570,7 +8570,7 @@ perft 5 21653203 perft 6 745802405 id 952 -epd rkrbb1nq/p2pppp1/1p4n1/2p4p/3N4/4P1P1/PPPP1P1P/RKRBBN1Q w CAca - 0 9 +epd rkrbb1nq/p2pppp1/1p4n1/2p4p/3N4/4P1P1/PPPP1P1P/RKRBBN1Q w CAca - perft 1 32 perft 2 697 perft 3 22231 @@ -8579,7 +8579,7 @@ perft 5 17150175 perft 6 441578567 id 953 -epd rkrnbb1q/pp2pp1p/6pn/2pp4/2B1P2P/8/PPPP1PP1/RKRNB1NQ w CAca - 0 9 +epd rkrnbb1q/pp2pp1p/6pn/2pp4/2B1P2P/8/PPPP1PP1/RKRNB1NQ w CAca - perft 1 28 perft 2 854 perft 3 23853 @@ -8588,7 +8588,7 @@ perft 5 21823412 perft 6 712787248 id 954 -epd rk2bnqb/pprpppp1/4n2p/2p5/P7/3P2NP/1PP1PPP1/RKRNB1QB w CAa - 1 9 +epd rk2bnqb/pprpppp1/4n2p/2p5/P7/3P2NP/1PP1PPP1/RKRNB1QB w CAa - perft 1 26 perft 2 596 perft 3 16251 @@ -8597,7 +8597,7 @@ perft 5 11758184 perft 6 323043654 id 955 -epd r1krnnbq/pp1ppp1p/6p1/2p5/2P5/P3P3/Rb1P1PPP/1BKRNNBQ w Dda - 0 9 +epd r1krnnbq/pp1ppp1p/6p1/2p5/2P5/P3P3/Rb1P1PPP/1BKRNNBQ w Dda - perft 1 2 perft 2 61 perft 3 1312 @@ -8606,7 +8606,7 @@ perft 5 937188 perft 6 28753562 id 956 -epd 1krbnnbq/1pp1p1pp/r7/p2p1p2/3PP3/2P3P1/PP3P1P/RKRBNNBQ w CAc - 0 9 +epd 1krbnnbq/1pp1p1pp/r7/p2p1p2/3PP3/2P3P1/PP3P1P/RKRBNNBQ w CAc - perft 1 30 perft 2 953 perft 3 28033 @@ -8615,7 +8615,7 @@ perft 5 25531358 perft 6 787205262 id 957 -epd rkr1nbbq/2ppp1pp/1pn5/p4p2/P6P/3P4/1PP1PPPB/RKRNNB1Q w CAca - 1 9 +epd rkr1nbbq/2ppp1pp/1pn5/p4p2/P6P/3P4/1PP1PPPB/RKRNNB1Q w CAca - perft 1 24 perft 2 645 perft 3 15689 @@ -8624,7 +8624,7 @@ perft 5 11484012 perft 6 341262639 id 958 -epd rkrnnqbb/p1ppp2p/Qp6/4Pp2/5p2/8/PPPP2PP/RKRNN1BB w CAca - 0 9 +epd rkrnnqbb/p1ppp2p/Qp6/4Pp2/5p2/8/PPPP2PP/RKRNN1BB w CAca - perft 1 35 perft 2 929 perft 3 32020 @@ -8633,7 +8633,7 @@ perft 5 31272517 perft 6 915268405 id 959 -epd bbq1nr1r/pppppk1p/2n2p2/6p1/P4P2/4P1P1/1PPP3P/BBQNNRKR w HF - 1 9 +epd bbq1nr1r/pppppk1p/2n2p2/6p1/P4P2/4P1P1/1PPP3P/BBQNNRKR w HF - perft 1 23 perft 2 589 perft 3 14744 From eaa6eb3b023e92441f9de810785bb1716dd4d0b5 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 4 May 2024 18:03:34 +0200 Subject: [PATCH 172/250] Fixup invalid EPD in crazyhouse.perft file --- examples/perft/crazyhouse.perft | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/perft/crazyhouse.perft b/examples/perft/crazyhouse.perft index 42ccd68a6..ef07eac04 100644 --- a/examples/perft/crazyhouse.perft +++ b/examples/perft/crazyhouse.perft @@ -18,7 +18,7 @@ perft 3 58057 perft 4 2083382 id zh-promoted -epd 4k3/1Q~6/8/8/4b3/8/Kpp5/8/ b - - 0 1 +epd 4k3/1Q~6/8/8/4b3/8/Kpp5/8/ b - - perft 1 20 perft 2 360 perft 3 5445 From 122963b82e408417e2b4fd17643a61f42f4e9ae9 Mon Sep 17 00:00:00 2001 From: 3d12 <3d12@users.noreply.github.com> Date: Thu, 16 May 2024 20:09:41 -0500 Subject: [PATCH 173/250] Add rookognition --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 7a677a451..c80957a37 100644 --- a/README.rst +++ b/README.rst @@ -351,6 +351,7 @@ If you like, share interesting things you are using python-chess for, for exampl * a `browser based PGN viewer `_ written in PyScript – https://github.com/nmstoker/ChessMatchViewer * an accessible chessboard that allows blind and visually impaired players to play chess against Stockfish – https://github.com/blindpandas/chessmart * analyse games to extract various statistics – https://github.com/mvrozanti/chess-playground +* a web-based chess vision exercise – https://github.com/3d12/rookognition Prior art From 102542a3c07c74557038ced2086c0d9bbb813cf4 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 26 May 2024 03:46:30 -0700 Subject: [PATCH 174/250] Remove GameNodeComment class Changes PR to a simpler change that is not backwards compatible. --- chess/pgn.py | 196 +++++++++++---------------------------------------- test.py | 66 +++++++---------- 2 files changed, 65 insertions(+), 197 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index e462a0750..b40ce257c 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -130,6 +130,10 @@ def repl(match: typing.Match[str]) -> str: return repl +def _standardize_comments(comment: Union[str, list[str]]) -> list[str]: + return [] if not comment else [comment] if isinstance(comment, str) else comment + + TAG_ROSTER = ["Event", "Site", "Date", "Round", "White", "Black", "Result"] @@ -184,92 +188,6 @@ def __init__(self, node: ChildNode, *, is_variation: bool = False, sidelines: bo self.in_variation = False -class GameNodeComment: - """ - PGN Comment Storage - - A class that can hold one or more comments for a GameNode. - """ - - def __init__(self, comment: Union[str, list[str], GameNodeComment] = ""): - """Create a new comment.""" - self.set(comment._comments if isinstance(comment,GameNodeComment) else comment) - - def set(self, new_comment: Union[str, list[str]]) -> None: - """Replace the comment with a new comment or a list of comments.""" - self._comments = new_comment if isinstance(new_comment, list) else [new_comment] if new_comment else [] - - def pgn_format(self) -> str: - """Create a string representation of the comments in PGN format.""" - comments = map(lambda s: s.replace("{", ""), self._comments) - comments = map(lambda s: s.replace("}", "").strip(), comments) - return " ".join(f"{{ {comment} }}" for comment in comments if comment) - - def remove_empty(self) -> None: - """Remove empty comments from the comment list.""" - self._comments = list(filter(None, self._comments)) - - def append(self, new_comment: Union[str, list[str]]) -> None: - """Append one or more new comments to the end of the comment list.""" - if new_comment: - if isinstance(new_comment, str): - self._comments.append(new_comment) - else: - self._comments.extend(new_comment) - - def insert(self, index: int, new_comment: str) -> None: - """Insert a new comment before the specified index.""" - self._comments.insert(index, new_comment) - - def pop(self, index: int = -1) -> None: - """Delete comment at the given index (default is the last comment).""" - self._comments.pop(index) - - def __len__(self) -> int: - """Get the number of comments in this node.""" - return len(self._comments) - - def __getitem__(self, index: int) -> str: - """Get the comment at the given index.""" - return self._comments[index] - - def __setitem__(self, index: int, new_comment: str) -> None: - """Change the comment at the given index.""" - self._comments[index] = new_comment - - def __iter__(self) -> Iterator[str]: - """Return an iterator over all comments.""" - return iter(self._comments) - - def __add__(self, other: Union[str, list[str], GameNodeComment]) -> GameNodeComment: - """Create a new comment set by adding two comment sets with +.""" - if isinstance(other, GameNodeComment): - return GameNodeComment(self._comments + other._comments) - else: - new_node_comment = GameNodeComment(self._comments.copy()) - new_node_comment.append(other) - return new_node_comment - - def __eq__(self, other: object) -> bool: - """Check for equality between two comment sets.""" - if isinstance(other, str): - return (len(self) == 1 and self[0] == other) or (not self and not other) - elif isinstance(other, list): - return self._comments == other - elif isinstance(other, GameNodeComment): - return self._comments == other._comments - else: - return False - - def __repr__(self) -> str: - """Return a code-like representation of the class.""" - return f"{self.__class__.__name__}({self._comments})" - - def __str__(self) -> str: - """Return a string representation of the comments in PGN format.""" - return self.pgn_format() - - class GameNode(abc.ABC): parent: Optional[GameNode] """The parent node or ``None`` if this is the root node of the game.""" @@ -283,45 +201,13 @@ class GameNode(abc.ABC): variations: List[ChildNode] """A list of child nodes.""" - _comment: GameNodeComment + comments: list[str] """ A comment that goes behind the move leading to this node. Comments that occur before any moves are assigned to the root node. """ - @property - def comment(self) -> str: - return " ".join(self._comment) - - @comment.setter - def comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self._comment = GameNodeComment(new_comment) - - @property - def comments(self) -> GameNodeComment: - return self._comment - - @comments.setter - def comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self._comment = GameNodeComment(new_comment) - - _starting_comment: GameNodeComment - - @property - def starting_comment(self) -> str: - return " ".join(self._starting_comment) - - @starting_comment.setter - def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self._starting_comment = GameNodeComment(new_comment) - - @property - def starting_comments(self) -> GameNodeComment: - return self._starting_comment - - @starting_comments.setter - def starting_comments(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self._starting_comment = GameNodeComment(new_comment) + starting_comments: list[str] nags: Set[int] @@ -329,11 +215,11 @@ def __init__(self, *, comment: Union[str, list[str]] = "") -> None: self.parent = None self.move = None self.variations = [] - self.comments = GameNodeComment(comment) + self.comments = _standardize_comments(comment) # Deprecated: These should be properties of ChildNode, but need to # remain here for backwards compatibility. - self.starting_comments = GameNodeComment() + self.starting_comments = [] self.nags = set() @abc.abstractmethod @@ -549,7 +435,8 @@ def add_line(self, moves: Iterable[chess.Move], *, comment: Union[str, list[str] starting_comment = "" # Merge comment and NAGs. - node.comments.append(comment) + comments = _standardize_comments(comment) + node.comments.extend(comments) node.nags.update(nags) return node @@ -561,7 +448,7 @@ def eval(self) -> Optional[chess.engine.PovScore]: Complexity is `O(n)`. """ - match = EVAL_REGEX.search(self.comment) + match = EVAL_REGEX.search(" ".join(self.comments)) if not match: return None @@ -587,7 +474,7 @@ def eval_depth(self) -> Optional[int]: Complexity is `O(1)`. """ - match = EVAL_REGEX.search(self.comment) + match = EVAL_REGEX.search(" ".join(self.comments)) return int(match.group("depth")) if match and match.group("depth") else None def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] = None) -> None: @@ -610,7 +497,7 @@ def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] if found: break - self.comments.remove_empty() + self.comments = list(filter(None, self.comments)) if not found and eval: self.comments.append(eval) @@ -623,7 +510,7 @@ def arrows(self) -> List[chess.svg.Arrow]: Returns a list of :class:`arrows `. """ arrows = [] - for match in ARROWS_REGEX.finditer(self.comment): + for match in ARROWS_REGEX.finditer(" ".join(self.comments)): for group in match.group("arrows").split(","): arrows.append(chess.svg.Arrow.from_pgn(group)) @@ -648,7 +535,7 @@ def set_arrows(self, arrows: Iterable[Union[chess.svg.Arrow, Tuple[Square, Squar for index in range(len(self.comments)): self.comments[index] = ARROWS_REGEX.sub(_condense_affix(""), self.comments[index]) - self.comments.remove_empty() + self.comments = list(filter(None, self.comments)) prefix = "" if csl: @@ -667,7 +554,7 @@ def clock(self) -> Optional[float]: Returns the player's remaining time to the next time control after this move, in seconds. """ - match = CLOCK_REGEX.search(self.comment) + match = CLOCK_REGEX.search(" ".join(self.comments)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -692,7 +579,7 @@ def set_clock(self, seconds: Optional[float]) -> None: if found: break - self.comments.remove_empty() + self.comments = list(filter(None, self.comments)) if not found and clk: self.comments.append(clk) @@ -705,7 +592,7 @@ def emt(self) -> Optional[float]: Returns the player's elapsed move time use for the comment of this move, in seconds. """ - match = EMT_REGEX.search(self.comment) + match = EMT_REGEX.search(" ".join(self.comments)) if match is None: return None return int(match.group("hours")) * 3600 + int(match.group("minutes")) * 60 + float(match.group("seconds")) @@ -730,7 +617,7 @@ def set_emt(self, seconds: Optional[float]) -> None: if found: break - self.comments.remove_empty() + self.comments = list(filter(None, self.comments)) if not found and emt: self.comments.append(emt) @@ -789,7 +676,7 @@ class ChildNode(GameNode): move: chess.Move """The move leading to this node.""" - _starting_comment: GameNodeComment + starting_comments: list[str] """ A comment for the start of a variation. Only nodes that actually start a variation (:func:`~chess.pgn.GameNode.starts_variation()` @@ -797,14 +684,6 @@ class ChildNode(GameNode): a starting comment. """ - @property - def starting_comment(self) -> str: - return " ".join(self._starting_comment) - - @starting_comment.setter - def starting_comment(self, new_comment: Union[str, list[str], GameNodeComment]) -> None: - self._starting_comment = GameNodeComment(new_comment) - nags: Set[int] """ A set of NAGs as integers. NAGs always go behind a move, so the root @@ -818,7 +697,7 @@ def __init__(self, parent: GameNode, move: chess.Move, *, comment: Union[str, li self.parent.variations.append(self) self.nags.update(nags) - self.starting_comments = GameNodeComment(starting_comment) + self.starting_comments = _standardize_comments(starting_comment) def board(self) -> chess.Board: stack: List[chess.Move] = [] @@ -874,7 +753,7 @@ def end(self) -> ChildNode: return typing.cast(ChildNode, super().end()) def _accept_node(self, parent_board: chess.Board, visitor: BaseVisitor[ResultT]) -> None: - if self.starting_comment: + if self.starting_comments: visitor.visit_comment(self.starting_comments) visitor.visit_move(parent_board, self.move) @@ -1270,7 +1149,7 @@ def visit_board(self, board: chess.Board) -> None: """ pass - def visit_comment(self, comment: GameNodeComment) -> None: + def visit_comment(self, comment: list[str]) -> None: """Called for each comment.""" pass @@ -1324,7 +1203,7 @@ def begin_game(self) -> None: self.game: GameT = self.Game() self.variation_stack: List[GameNode] = [self.game] - self.starting_comment = GameNodeComment() + self.starting_comments: list[str] = [] self.in_variation = False def begin_headers(self) -> Headers: @@ -1349,24 +1228,23 @@ def visit_result(self, result: str) -> None: if self.game.headers.get("Result", "*") == "*": self.game.headers["Result"] = result - def visit_comment(self, comment: GameNodeComment) -> None: + def visit_comment(self, comment: Union[str, list[str]]) -> None: + comments = _standardize_comments(comment) if self.in_variation or (self.variation_stack[-1].parent is None and self.variation_stack[-1].is_end()): # Add as a comment for the current node if in the middle of # a variation. Add as a comment for the game if the comment # starts before any move. - new_comments = self.variation_stack[-1].comments + comment - new_comments.remove_empty() - self.variation_stack[-1].comments = new_comments + self.variation_stack[-1].comments.extend(comments) + self.variation_stack[-1].comments = list(filter(None, self.variation_stack[-1].comments)) else: # Otherwise, it is a starting comment. - new_comments = self.starting_comment + comment - new_comments.remove_empty() - self.starting_comment = new_comments + self.starting_comments.extend(comments) + self.starting_comments = list(filter(None, self.starting_comments)) def visit_move(self, board: chess.Board, move: chess.Move) -> None: self.variation_stack[-1] = self.variation_stack[-1].add_variation(move) - self.variation_stack[-1].starting_comments = self.starting_comment - self.starting_comment = GameNodeComment() + self.variation_stack[-1].starting_comments = self.starting_comments + self.starting_comments = [] self.in_variation = True def handle_error(self, error: Exception) -> None: @@ -1534,9 +1412,15 @@ def end_variation(self) -> None: self.write_token(") ") self.force_movenumber = True - def visit_comment(self, comment: GameNodeComment) -> None: + def visit_comment(self, comment: Union[str, list[str]]) -> None: if self.comments and (self.variations or not self.variation_depth): - self.write_token(comment.pgn_format() + " ") + def pgn_format(comments: list[str]) -> str: + comments = map(lambda s: s.replace("{", ""), comments) + comments = map(lambda s: s.replace("}", ""), comments) + return " ".join(f"{{ {comment} }}" for comment in comments if comment) + + comments = _standardize_comments(comment) + self.write_token(pgn_format(comments) + " ") self.force_movenumber = True def visit_nag(self, nag: int) -> None: diff --git a/test.py b/test.py index 4baf2dc58..92afd8de7 100755 --- a/test.py +++ b/test.py @@ -2083,29 +2083,29 @@ class PgnTestCase(unittest.TestCase): def test_exporter(self): game = chess.pgn.Game() - game.comment = "Test game:" + game.comments = ["Test game:"] game.headers["Result"] = "*" game.headers["VeryLongHeader"] = "This is a very long header, much wider than the 80 columns that PGNs are formatted with by default" e4 = game.add_variation(game.board().parse_san("e4")) - e4.comment = "Scandinavian Defense:" + e4.comments = ["Scandinavian Defense:"] e4_d5 = e4.add_variation(e4.board().parse_san("d5")) e4_h5 = e4.add_variation(e4.board().parse_san("h5")) e4_h5.nags.add(chess.pgn.NAG_MISTAKE) - e4_h5.starting_comment = "This" - e4_h5.comment = "is nonsense" + e4_h5.starting_comments = ["This"] + e4_h5.comments = ["is nonsense"] e4_e5 = e4.add_variation(e4.board().parse_san("e5")) e4_e5_Qf3 = e4_e5.add_variation(e4_e5.board().parse_san("Qf3")) e4_e5_Qf3.nags.add(chess.pgn.NAG_MISTAKE) e4_c5 = e4.add_variation(e4.board().parse_san("c5")) - e4_c5.comment = "Sicilian" + e4_c5.comments = ["Sicilian"] e4_d5_exd5 = e4_d5.add_main_variation(e4_d5.board().parse_san("exd5")) - e4_d5_exd5.comment = ["Best", "and the end of this example"] + e4_d5_exd5.comments = ["Best", "and the end of this example"] # Test string exporter with various options. exporter = chess.pgn.StringExporter(headers=False, comments=False, variations=False) @@ -2224,26 +2224,16 @@ def test_read_game_with_multicomment_move(self): pgn = io.StringIO("1. e4 {A common opening} 1... e5 {A common response} {An uncommon comment}") game = chess.pgn.read_game(pgn) first_move = game.variation(0) - self.assertEqual(first_move.comment, "A common opening") - self.assertEqual(first_move.comments, "A common opening") self.assertEqual(first_move.comments, ["A common opening"]) second_move = first_move.variation(0) self.assertEqual(second_move.comments, ["A common response", "An uncommon comment"]) second_move.comments.pop() self.assertEqual(second_move.comments, ["A common response"]) - self.assertEqual(second_move.comments, "A common response") - self.assertEqual(second_move.comment, "A common response") second_move.comments.append("A replaced comment") multiple_comments = ["A common response", "A replaced comment"] self.assertEqual(second_move.comments, multiple_comments) - for move_comment, test_comment in zip(second_move.comments, multiple_comments): - self.assertEqual(move_comment, test_comment) - self.assertEqual(list(second_move.comments), multiple_comments) - self.assertEqual(second_move.comment, " ".join(multiple_comments)) second_move.comments.pop(0) self.assertEqual(second_move.comments, ["A replaced comment"]) - self.assertEqual(second_move.comments, "A replaced comment") - self.assertEqual(second_move.comment, "A replaced comment") def test_comment_at_eol(self): pgn = io.StringIO(textwrap.dedent("""\ @@ -2259,7 +2249,7 @@ def test_comment_at_eol(self): # Make sure the comment for the second variation is there. self.assertIn(5, node[1].nags) - self.assertEqual(node[1].comment, "\n/\\ Ne7, c6") + self.assertEqual(node[1].comments, ["\n/\\ Ne7, c6"]) def test_promotion_without_equals(self): # Example game from https://github.com/rozim/ChessData as originally @@ -2347,12 +2337,12 @@ def test_variation_stack(self): def test_game_starting_comment(self): pgn = io.StringIO("{ Game starting comment } 1. d3") game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, "Game starting comment") + self.assertEqual(game.comments, ["Game starting comment"]) self.assertEqual(game[0].san(), "d3") pgn = io.StringIO("{ Empty game, but has a comment }") game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, "Empty game, but has a comment") + self.assertEqual(game.comments, ["Empty game, but has a comment"]) def test_game_starting_variation(self): pgn = io.StringIO(textwrap.dedent("""\ @@ -2360,17 +2350,17 @@ def test_game_starting_variation(self): """)) game = chess.pgn.read_game(pgn) - self.assertEqual(game.comment, "Start of game") + self.assertEqual(game.comments, ["Start of game"]) node = game[0] self.assertEqual(node.move, chess.Move.from_uci("e2e4")) - self.assertFalse(node.comment) - self.assertFalse(node.starting_comment) + self.assertFalse(node.comments) + self.assertFalse(node.starting_comments) node = game[1] self.assertEqual(node.move, chess.Move.from_uci("d2d4")) - self.assertFalse(node.comment) - self.assertEqual(node.starting_comment, "Start of variation") + self.assertFalse(node.comments) + self.assertEqual(node.starting_comments, ["Start of variation"]) def test_annotation_symbols(self): pgn = io.StringIO("1. b4?! g6 2. Bb2 Nc6? 3. Bxh8!!") @@ -2715,12 +2705,12 @@ def test_add_line(self): tail = game.add_line(moves, starting_comment="start", comment="end", nags=(17, 42)) self.assertEqual(tail.parent.move, chess.Move.from_uci("g1f3")) - self.assertEqual(tail.parent.starting_comment, "start") - self.assertEqual(tail.parent.comment, "") + self.assertEqual(tail.parent.starting_comments, ["start"]) + self.assertEqual(tail.parent.comments, []) self.assertEqual(len(tail.parent.nags), 0) self.assertEqual(tail.move, chess.Move.from_uci("d7d5")) - self.assertEqual(tail.comment, "end") + self.assertEqual(tail.comments, ["end"]) self.assertIn(42, tail.nags) def test_mainline(self): @@ -2850,12 +2840,11 @@ def test_recursion(self): def test_annotations(self): game = chess.pgn.Game() - game.comment = "foo [%bar] baz" + game.comments = ["foo [%bar] baz"] self.assertTrue(game.clock() is None) clock = 12345 game.set_clock(clock) - self.assertEqual(game.comment, "foo [%bar] baz [%clk 3:25:45]") self.assertEqual(game.comments, ["foo [%bar] baz", "[%clk 3:25:45]"]) self.assertEqual(game.clock(), clock) @@ -2872,7 +2861,6 @@ def test_annotations(self): self.assertEqual(game.arrows(), []) game.set_arrows([(chess.A1, chess.A1), chess.svg.Arrow(chess.A1, chess.H1, color="red"), chess.svg.Arrow(chess.B1, chess.B8)]) self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]"]) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%eval #1,5]") arrows = game.arrows() self.assertEqual(len(arrows), 3) self.assertEqual(arrows[0].color, "green") @@ -2883,21 +2871,17 @@ def test_annotations(self): emt = 321 game.set_emt(emt) self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%eval #1,5]", "[%emt 0:05:21]"]) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%eval #1,5] [%emt 0:05:21]") self.assertEqual(game.emt(), emt) game.set_eval(None) self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]", "[%emt 0:05:21]"]) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45] [%emt 0:05:21]") game.set_emt(None) self.assertEqual(game.comments, ["[%csl Ga1][%cal Ra1h1,Gb1b8]", "foo [%bar] baz", "[%clk 3:25:45]"]) - self.assertEqual(game.comment, "[%csl Ga1][%cal Ra1h1,Gb1b8] foo [%bar] baz [%clk 3:25:45]") game.set_clock(None) game.set_arrows([]) - self.assertEqual(game.comments, "foo [%bar] baz") - self.assertEqual(game.comment, "foo [%bar] baz") + self.assertEqual(game.comments, ["foo [%bar] baz"]) def test_eval(self): game = chess.pgn.Game() @@ -2907,28 +2891,28 @@ def test_eval(self): def test_float_emt(self): game = chess.pgn.Game() - game.comment = "[%emt 0:00:01.234]" + game.comments = ["[%emt 0:00:01.234]"] self.assertEqual(game.emt(), 1.234) game.set_emt(6.54321) - self.assertEqual(game.comment, "[%emt 0:00:06.543]") + self.assertEqual(game.comments, ["[%emt 0:00:06.543]"]) self.assertEqual(game.emt(), 6.543) game.set_emt(-70) - self.assertEqual(game.comment, "[%emt 0:00:00]") # Clamped + self.assertEqual(game.comments, ["[%emt 0:00:00]"]) # Clamped self.assertEqual(game.emt(), 0) def test_float_clk(self): game = chess.pgn.Game() - game.comment = "[%clk 0:00:01.234]" + game.comments = ["[%clk 0:00:01.234]"] self.assertEqual(game.clock(), 1.234) game.set_clock(6.54321) - self.assertEqual(game.comment, "[%clk 0:00:06.543]") + self.assertEqual(game.comments, ["[%clk 0:00:06.543]"]) self.assertEqual(game.clock(), 6.543) game.set_clock(-70) - self.assertEqual(game.comment, "[%clk 0:00:00]") # Clamped + self.assertEqual(game.comments, ["[%clk 0:00:00]"]) # Clamped self.assertEqual(game.clock(), 0) def test_node_turn(self): From 52dc00154d10c230c0aa6ce13299d7a0c825f19a Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 26 May 2024 15:04:05 -0700 Subject: [PATCH 175/250] Convert map return type to list --- chess/pgn.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index b40ce257c..b999d79a6 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1415,8 +1415,8 @@ def end_variation(self) -> None: def visit_comment(self, comment: Union[str, list[str]]) -> None: if self.comments and (self.variations or not self.variation_depth): def pgn_format(comments: list[str]) -> str: - comments = map(lambda s: s.replace("{", ""), comments) - comments = map(lambda s: s.replace("}", ""), comments) + comments = list(map(lambda s: s.replace("{", ""), comments)) + comments = list(map(lambda s: s.replace("}", ""), comments)) return " ".join(f"{{ {comment} }}" for comment in comments if comment) comments = _standardize_comments(comment) From 3b23452ee5728d1ec75e2cbf6f1c208e0416a9ee Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Sun, 26 May 2024 15:14:13 -0700 Subject: [PATCH 176/250] Remove tests of python list methods --- test.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test.py b/test.py index 92afd8de7..cf5439547 100755 --- a/test.py +++ b/test.py @@ -2227,13 +2227,6 @@ def test_read_game_with_multicomment_move(self): self.assertEqual(first_move.comments, ["A common opening"]) second_move = first_move.variation(0) self.assertEqual(second_move.comments, ["A common response", "An uncommon comment"]) - second_move.comments.pop() - self.assertEqual(second_move.comments, ["A common response"]) - second_move.comments.append("A replaced comment") - multiple_comments = ["A common response", "A replaced comment"] - self.assertEqual(second_move.comments, multiple_comments) - second_move.comments.pop(0) - self.assertEqual(second_move.comments, ["A replaced comment"]) def test_comment_at_eol(self): pgn = io.StringIO(textwrap.dedent("""\ From 3829d262c325b61b0004a314347f985008a9eb84 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 17 Jun 2024 21:18:43 +0200 Subject: [PATCH 177/250] Factor out Tablebase.add_file() --- chess/syzygy.py | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index e1fe07eb7..0c7d41500 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1511,27 +1511,23 @@ def add_directory(self, directory: str, *, load_wdl: bool = True, load_dtz: bool Returns the number of table files that were found. """ - num = 0 directory = os.path.abspath(directory) - - for filename in os.listdir(directory): - path = os.path.join(directory, filename) - tablename, ext = os.path.splitext(filename) - - if is_tablename(tablename, one_king=self.variant.one_king) and os.path.isfile(path): - if load_wdl: - if ext == self.variant.tbw_suffix: - num += self._open_table(self.wdl, WdlTable, path) - elif "P" not in tablename and ext == self.variant.pawnless_tbw_suffix: - num += self._open_table(self.wdl, WdlTable, path) - - if load_dtz: - if ext == self.variant.tbz_suffix: - num += self._open_table(self.dtz, DtzTable, path) - elif "P" not in tablename and ext == self.variant.pawnless_tbz_suffix: - num += self._open_table(self.dtz, DtzTable, path) - - return num + return sum(self.add_file(os.path.join(directory, filename), load_wdl=load_wdl, load_dtz=load_dtz) for filename in os.listdir(directory)) + + def add_file(self, path: str, *, load_wdl: bool = True, load_dtz: bool = True) -> int: + tablename, ext = os.path.splitext(os.path.basename(path)) + if is_tablename(tablename, one_king=self.variant.one_king) and os.path.isfile(path): + if load_wdl: + if ext == self.variant.tbw_suffix: + return self._open_table(self.wdl, WdlTable, path) + elif "P" not in tablename and ext == self.variant.pawnless_tbw_suffix: + return self._open_table(self.wdl, WdlTable, path) + if load_dtz: + if ext == self.variant.tbz_suffix: + return self._open_table(self.dtz, DtzTable, path) + elif "P" not in tablename and ext == self.variant.pawnless_tbz_suffix: + return self._open_table(self.dtz, DtzTable, path) + return 0 def probe_wdl_table(self, board: chess.Board) -> int: # Test for variant end. From a41c3c88022fd97ab0eaf7b032a3158b69628b66 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 4 Jul 2024 16:41:19 +0200 Subject: [PATCH 178/250] Do not eagerly check syzygy max pieces (fixes #1093) --- chess/syzygy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 0c7d41500..807b0922e 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1546,6 +1546,8 @@ def probe_wdl_table(self, board: chess.Board) -> int: try: table = typing.cast(WdlTable, self.wdl[key]) except KeyError: + if chess.popcount(board.occupied) > TBPIECES: + raise KeyError(f"syzygy tables support up to {TBPIECES} pieces, not {chess.popcount(board.occupied)}: {board.fen()}") raise MissingTableError(f"did not find wdl table {key}") self._bump_lru(table) @@ -1558,8 +1560,6 @@ def probe_ab(self, board: chess.Board, alpha: int, beta: int, threats: bool = Fa raise KeyError(f"tablebase has been opened for {self.variant.uci_variant}, probed with: {board.uci_variant}") if board.castling_rights: raise KeyError(f"syzygy tables do not contain positions with castling rights: {board.fen()}") - if chess.popcount(board.occupied) > TBPIECES: - raise KeyError(f"syzygy tables support up to {TBPIECES} pieces, not {chess.popcount(board.occupied)}: {board.fen()}") # Special case: Variant with compulsory captures. if self.variant.captures_compulsory: From 95803fc64a89307bfe51910f9e9349d120b81705 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 4 Jul 2024 20:58:32 +0200 Subject: [PATCH 179/250] Artificially limit syzygy ab search after relaxing bound --- chess/syzygy.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/chess/syzygy.py b/chess/syzygy.py index 807b0922e..8ba1cbca4 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1561,6 +1561,13 @@ def probe_ab(self, board: chess.Board, alpha: int, beta: int, threats: bool = Fa if board.castling_rights: raise KeyError(f"syzygy tables do not contain positions with castling rights: {board.fen()}") + # Probing resolves captures, so sometimes we can obtain results for + # positions that have more pieces than the maximum number of supported + # pieces. We artificially limit this to one additional level, to + # make sure search remains somewhat bounded. + if chess.popcount(board.occupied) > TBPIECES + 1: + raise KeyError(f"syzygy tables support up to {TBPIECES} pieces, not {chess.popcount(board.occupied)}: {board.fen()}") + # Special case: Variant with compulsory captures. if self.variant.captures_compulsory: if board.is_variant_win(): From 474c87bfcccb8e2aa78a4a94414af3b747340f31 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 10 Jul 2024 18:02:09 +0200 Subject: [PATCH 180/250] Add another SAN disambiguation test (niklasf/shakmaty#77) --- test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test.py b/test.py index 4ca3be6c2..00d766a03 100755 --- a/test.py +++ b/test.py @@ -703,6 +703,11 @@ def test_san(self): self.assertEqual(board.san(chess.Move.from_uci("h4g6")), "Nh4g6") self.assertEqual(board.fen(), fen) + # Test a bug where shakmaty used overly specific disambiguation. + fen = "8/2KN1p2/5p2/3N1B1k/5PNp/7P/7P/8 w - -" + board = chess.Board(fen) + self.assertEqual(board.san(chess.Move.from_uci("d5f6")), "N5xf6#") + # Do not disambiguate illegal alternatives. fen = "8/8/8/R2nkn2/8/8/2K5/8 b - - 0 1" board = chess.Board(fen) From ec8ecec5c0277691ec76041e82bf13140f7f719a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 11 Jul 2024 16:03:22 +0200 Subject: [PATCH 181/250] chess-playground discontinued --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index c80957a37..a6c3185c6 100644 --- a/README.rst +++ b/README.rst @@ -350,7 +350,6 @@ If you like, share interesting things you are using python-chess for, for exampl * Django Rest Framework API for multiplayer chess – https://github.com/WorkShoft/capablanca-api * a `browser based PGN viewer `_ written in PyScript – https://github.com/nmstoker/ChessMatchViewer * an accessible chessboard that allows blind and visually impaired players to play chess against Stockfish – https://github.com/blindpandas/chessmart -* analyse games to extract various statistics – https://github.com/mvrozanti/chess-playground * a web-based chess vision exercise – https://github.com/3d12/rookognition From 63aac2ec65860a64256a190220b793e80b132b50 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 19 Jul 2024 16:31:22 +0200 Subject: [PATCH 182/250] Expose optional occupied parameter for attackers_mask (#1090) --- chess/__init__.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index bed9eec5d..a90df9ef6 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -902,7 +902,9 @@ def attacks(self, square: Square) -> SquareSet: """ return SquareSet(self.attacks_mask(square)) - def _attackers_mask(self, color: Color, square: Square, occupied: Bitboard) -> Bitboard: + def attackers_mask(self, color: Color, square: Square, occupied: Optional[Bitboard] = None) -> Bitboard: + occupied = self.occupied if occupied is None else occupied + rank_pieces = BB_RANK_MASKS[square] & occupied file_pieces = BB_FILE_MASKS[square] & occupied diag_pieces = BB_DIAG_MASKS[square] & occupied @@ -920,27 +922,38 @@ def _attackers_mask(self, color: Color, square: Square, occupied: Bitboard) -> B return attackers & self.occupied_co[color] - def attackers_mask(self, color: Color, square: Square) -> Bitboard: - return self._attackers_mask(color, square, self.occupied) - - def is_attacked_by(self, color: Color, square: Square) -> bool: + def is_attacked_by(self, color: Color, square: Square, occupied: Optional[IntoSquareSet] = None) -> bool: """ Checks if the given side attacks the given square. Pinned pieces still count as attackers. Pawns that can be captured en passant are **not** considered attacked. + + *occupied* determines which squares are considered to block attacks. + For example, + ``board.occupied ^ board.pieces_mask(chess.KING, board.turn)`` can be + used to consider X-ray attacks through the king. + Defaults to ``board.occupied`` (all pieces including the king, + no X-ray attacks). """ - return bool(self.attackers_mask(color, square)) + return bool(self.attackers_mask(color, square, None if occupied is None else SquareSet(occupied).mask)) - def attackers(self, color: Color, square: Square) -> SquareSet: + def attackers(self, color: Color, square: Square, occupied: Optional[IntoSquareSet] = None) -> SquareSet: """ Gets the set of attackers of the given color for the given square. Pinned pieces still count as attackers. + *occupied* determines which squares are considered to block attacks. + For example, + ``board.occupied ^ board.pieces_mask(chess.KING, board.turn)`` can be + used to consider X-ray attacks through the king. + Defaults to ``board.occupied`` (all pieces including the king, + no X-ray attacks). + Returns a :class:`set of squares `. """ - return SquareSet(self.attackers_mask(color, square)) + return SquareSet(self.attackers_mask(color, square, None if occupied is None else SquareSet(occupied).mask)) def pin_mask(self, color: Color, square: Square) -> Bitboard: king = self.king(color) @@ -3723,7 +3736,7 @@ def generate_legal_captures(self, from_mask: Bitboard = BB_ALL, to_mask: Bitboar self.generate_legal_ep(from_mask, to_mask)) def _attacked_for_king(self, path: Bitboard, occupied: Bitboard) -> bool: - return any(self._attackers_mask(not self.turn, sq, occupied) for sq in scan_reversed(path)) + return any(self.attackers_mask(not self.turn, sq, occupied) for sq in scan_reversed(path)) def generate_castling_moves(self, from_mask: Bitboard = BB_ALL, to_mask: Bitboard = BB_ALL) -> Iterator[Move]: if self.is_variant_end(): From 7836d446bf0cfc3b265e038fa381a7e52a543c41 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 19 Jul 2024 16:41:25 +0200 Subject: [PATCH 183/250] Add chess.svg.SvgWrapper._repr_html_() (closes #1096) --- chess/svg.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chess/svg.py b/chess/svg.py index d3d19e89e..2948b0b80 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -144,6 +144,9 @@ class SvgWrapper(str): def _repr_svg_(self) -> SvgWrapper: return self + def _repr_html_(self) -> SvgWrapper: + return self + def _svg(viewbox: int, size: Optional[int]) -> ET.Element: svg = ET.Element("svg", { From 247d8a06a6b2c2dc06f9ce0b7f3e94dbd9b816bd Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 19 Jul 2024 17:27:12 +0200 Subject: [PATCH 184/250] Update changelog for soon to be released final 1.x --- CHANGELOG.rst | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0fa76effa..a4534badb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,9 +6,26 @@ Upcoming in the next release Changes: -* Dropped support for Python 3.7, which had reached its end of life. -* `chess.engine.EventLoopPolicy` is no longer needed and now merely an alias +* Drop support for Python 3.7, which has reached its end of life. +* ``chess.engine.EventLoopPolicy`` is no longer needed and now merely an alias for the default event loop policy. +* If available and requested via ``setpgrp``, use ``process_group`` support + from Python 3.11 for engine processes. +* No longer eagerly reject 8 piece positions in ``chess.syzygy``, so that + some 8 piece positions with decisive captures can be probed successfully. +* The string wrapper returned by ``chess.svg`` functions now also implements + ``_repr_html_``. + +New features: + +* Add ``chess.pgn.Game.time_control()`` and related data models. +* Add model ``sf16.1`` for ``chess.engine.Score.wdl()``, the new default. + +Bugfixes: + +* Fix handling of whitespace in UCI engine communication. +* For ``chess.Board.epd()`` and ``chess.Board.set_epd()``, require that EPD + opcodes start with a letter. New in v1.10.0 (27th Jul 2023) ------------------------------ From c7199a6354fe3053235c8ad88d79714afccdc0b9 Mon Sep 17 00:00:00 2001 From: Deepyaman Datta Date: Sun, 21 Jul 2024 22:42:48 -0600 Subject: [PATCH 185/250] Update default time control from UNKNOW to UNKNOWN --- chess/pgn.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 55eddbc29..0d0879ae0 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -143,7 +143,7 @@ class SkipType(enum.Enum): class TimeControlType(enum.Enum): - UNKNOW = 0 + UNKNOWN = 0 UNLIMITED = 1 STANDARD = 2 RAPID = 3 @@ -172,7 +172,7 @@ class TimeControl: """ parts: list[TimeControlPart] = dataclasses.field(default_factory=list) - type: TimeControlType = TimeControlType.UNKNOW + type: TimeControlType = TimeControlType.UNKNOWN class _AcceptFrame: From ad6f756c4406d66a59a9cd1050f50137de84dc30 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 31 Jul 2024 00:04:57 -0700 Subject: [PATCH 186/250] Factor out repeated annotation editing code --- chess/pgn.py | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index b999d79a6..b8cfbe440 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -491,16 +491,7 @@ def set_eval(self, score: Optional[chess.engine.PovScore], depth: Optional[int] elif score.white().mate(): eval = f"[%eval #{score.white().mate()}{depth_suffix}]" - found = 0 - for index in range(len(self.comments)): - self.comments[index], found = EVAL_REGEX.subn(_condense_affix(eval), self.comments[index], count=1) - if found: - break - - self.comments = list(filter(None, self.comments)) - - if not found and eval: - self.comments.append(eval) + self._replace_or_add_annotation(eval, EVAL_REGEX) def arrows(self) -> List[chess.svg.Arrow]: """ @@ -573,16 +564,7 @@ def set_clock(self, seconds: Optional[float]) -> None: seconds_part = f"{seconds:06.3f}".rstrip("0").rstrip(".") clk = f"[%clk {hours:d}:{minutes:02d}:{seconds_part}]" - found = 0 - for index in range(len(self.comments)): - self.comments[index], found = CLOCK_REGEX.subn(_condense_affix(clk), self.comments[index], count=1) - if found: - break - - self.comments = list(filter(None, self.comments)) - - if not found and clk: - self.comments.append(clk) + self._replace_or_add_annotation(clk, CLOCK_REGEX) def emt(self) -> Optional[float]: """ @@ -611,16 +593,19 @@ def set_emt(self, seconds: Optional[float]) -> None: seconds_part = f"{seconds:06.3f}".rstrip("0").rstrip(".") emt = f"[%emt {hours:d}:{minutes:02d}:{seconds_part}]" + self._replace_or_add_annotation(emt, EMT_REGEX) + + def _replace_or_add_annotation(self, text: str, regex: re.Pattern[str]) -> None: found = 0 for index in range(len(self.comments)): - self.comments[index], found = EMT_REGEX.subn(_condense_affix(emt), self.comments[index], count=1) + self.comments[index], found = regex.subn(_condense_affix(text), self.comments[index], count=1) if found: break self.comments = list(filter(None, self.comments)) - if not found and emt: - self.comments.append(emt) + if not found and text: + self.comments.append(text) @abc.abstractmethod def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: From 744d2fcae0b2c9d26007648099094b05475bb5cc Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 31 Jul 2024 00:48:02 -0700 Subject: [PATCH 187/250] Lazily remove curly braces from comments --- chess/pgn.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index c7d4a87a3..3acf66401 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1400,9 +1400,8 @@ def end_variation(self) -> None: def visit_comment(self, comment: Union[str, list[str]]) -> None: if self.comments and (self.variations or not self.variation_depth): def pgn_format(comments: list[str]) -> str: - comments = list(map(lambda s: s.replace("{", ""), comments)) - comments = list(map(lambda s: s.replace("}", ""), comments)) - return " ".join(f"{{ {comment} }}" for comment in comments if comment) + edit = map(lambda s: s.replace("{", "").replace("}", ""), comments) + return " ".join(f"{{ {comment} }}" for comment in edit if comment) comments = _standardize_comments(comment) self.write_token(pgn_format(comments) + " ") From dce369c6388805b5ac51c8b9b765e4da33f09795 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Wed, 31 Jul 2024 00:48:28 -0700 Subject: [PATCH 188/250] Add test for removing curly braces from comments --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index 23ecab2fc..2a4f551ea 100755 --- a/test.py +++ b/test.py @@ -2110,7 +2110,7 @@ def test_exporter(self): e4_c5.comments = ["Sicilian"] e4_d5_exd5 = e4_d5.add_main_variation(e4_d5.board().parse_san("exd5")) - e4_d5_exd5.comments = ["Best", "and the end of this example"] + e4_d5_exd5.comments = ["Best", "and the end of this {example}"] # Test string exporter with various options. exporter = chess.pgn.StringExporter(headers=False, comments=False, variations=False) From dda9e8fedc75eefb0255245abff0782ecb26f882 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 15:09:53 +0200 Subject: [PATCH 189/250] Refactor chess.engine.BaseCommand to pass stricter type checking --- chess/engine.py | 614 +++++++++++++++++++++++++++--------------------- 1 file changed, 344 insertions(+), 270 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c2b470dd5..d1bbaaee1 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -24,6 +24,9 @@ from types import TracebackType from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypedDict, TypeVar, Union +if typing.TYPE_CHECKING: + from typing_extensions import Self + WdlModel = Literal["sf", "sf16.1", "sf16", "sf15.1", "sf15", "sf14", "sf12", "lichess"] @@ -895,7 +898,7 @@ class Protocol(asyncio.SubprocessProtocol, metaclass=abc.ABCMeta): returncode: asyncio.Future[int] """Future: Exit code of the process.""" - def __init__(self: ProtocolT) -> None: + def __init__(self) -> None: self.loop = asyncio.get_running_loop() self.transport: Optional[asyncio.SubprocessTransport] = None @@ -904,8 +907,8 @@ def __init__(self: ProtocolT) -> None: 2: bytearray(), # stderr } - self.command: Optional[BaseCommand[ProtocolT, Any]] = None - self.next_command: Optional[BaseCommand[ProtocolT, Any]] = None + self.command: Optional[BaseCommand[Any]] = None + self.next_command: Optional[BaseCommand[Any]] = None self.initialized = False self.returncode: asyncio.Future[int] = asyncio.Future() @@ -915,7 +918,7 @@ def connection_made(self, transport: asyncio.BaseTransport) -> None: self.transport = transport # type: ignore LOGGER.debug("%s: Connection made", self) - def connection_lost(self: ProtocolT, exc: Optional[Exception]) -> None: + def connection_lost(self, exc: Optional[Exception]) -> None: assert self.transport is not None code = self.transport.get_returncode() assert code is not None, "connect lost, but got no returncode" @@ -923,10 +926,10 @@ def connection_lost(self: ProtocolT, exc: Optional[Exception]) -> None: # Terminate commands. if self.command is not None: - self.command._engine_terminated(self, code) + self.command._engine_terminated(code) self.command = None if self.next_command is not None: - self.next_command._engine_terminated(self, code) + self.next_command._engine_terminated(code) self.next_command = None self.returncode.set_result(code) @@ -960,18 +963,18 @@ def pipe_data_received(self, fd: int, data: Union[bytes, str]) -> None: def error_line_received(self, line: str) -> None: LOGGER.warning("%s: stderr >> %s", self, line) - def _line_received(self: ProtocolT, line: str) -> None: + def _line_received(self: Protocol, line: str) -> None: LOGGER.debug("%s: >> %s", self, line) self.line_received(line) if self.command: - self.command._line_received(self, line) + self.command._line_received(line) def line_received(self, line: str) -> None: pass - async def communicate(self: ProtocolT, command_factory: Callable[[ProtocolT], BaseCommand[ProtocolT, T]]) -> T: + async def communicate(self, command_factory: Callable[[Self], BaseCommand[T]]) -> T: command = command_factory(self) if self.returncode.done(): @@ -993,18 +996,18 @@ def previous_command_finished(_: Optional[asyncio.Future[None]]) -> None: def cancel_if_cancelled(result: asyncio.Future[T]) -> None: if result.cancelled(): - cmd._cancel(self) + cmd._cancel() cmd.result.add_done_callback(cancel_if_cancelled) cmd.finished.add_done_callback(previous_command_finished) - cmd._start(self) + cmd._start() if self.command is None: previous_command_finished(None) elif not self.command.result.done(): self.command.result.cancel() elif not self.command.result.cancelled(): - self.command._cancel(self) + self.command._cancel() return await command.result @@ -1207,32 +1210,34 @@ class CommandState(enum.Enum): DONE = enum.auto() -class BaseCommand(Generic[ProtocolT, T]): - def __init__(self, engine: ProtocolT) -> None: +class BaseCommand(Generic[T]): + def __init__(self, engine: Protocol) -> None: + self._engine = engine + self.state = CommandState.NEW self.result: asyncio.Future[T] = asyncio.Future() self.finished: asyncio.Future[None] = asyncio.Future() - def _engine_terminated(self, engine: ProtocolT, code: int) -> None: + def _engine_terminated(self, code: int) -> None: hint = ", binary not compatible with cpu?" if code in [-4, 0xc000001d] else "" exc = EngineTerminatedError(f"engine process died unexpectedly (exit code: {code}{hint})") if self.state == CommandState.ACTIVE: - self.engine_terminated(engine, exc) + self.engine_terminated(exc) elif self.state == CommandState.CANCELLING: self.finished.set_result(None) elif self.state == CommandState.NEW: - self._handle_exception(engine, exc) + self._handle_exception(exc) - def _handle_exception(self, engine: ProtocolT, exc: Exception) -> None: + def _handle_exception(self, exc: Exception) -> None: if not self.result.done(): self.result.set_exception(exc) else: - engine.loop.call_exception_handler({ + self._engine.loop.call_exception_handler({ # XXX "message": f"{type(self).__name__} failed after returning preliminary result ({self.result!r})", "exception": exc, - "protocol": engine, - "transport": engine.transport, + "protocol": self._engine, + "transport": self._engine.transport, }) if not self.finished.done(): @@ -1245,43 +1250,43 @@ def set_finished(self) -> None: self.finished.set_result(None) self.state = CommandState.DONE - def _cancel(self, engine: ProtocolT) -> None: + def _cancel(self) -> None: if self.state != CommandState.CANCELLING and self.state != CommandState.DONE: assert self.state == CommandState.ACTIVE self.state = CommandState.CANCELLING - self.cancel(engine) + self.cancel() - def _start(self, engine: ProtocolT) -> None: + def _start(self) -> None: assert self.state == CommandState.NEW self.state = CommandState.ACTIVE try: - self.check_initialized(engine) - self.start(engine) + self.check_initialized() + self.start() except EngineError as err: - self._handle_exception(engine, err) + self._handle_exception(err) - def _line_received(self, engine: ProtocolT, line: str) -> None: + def _line_received(self, line: str) -> None: assert self.state in [CommandState.ACTIVE, CommandState.CANCELLING] try: - self.line_received(engine, line) + self.line_received(line) except EngineError as err: - self._handle_exception(engine, err) + self._handle_exception(err) - def cancel(self, engine: ProtocolT) -> None: + def cancel(self) -> None: pass - def check_initialized(self, engine: ProtocolT) -> None: - if not engine.initialized: + def check_initialized(self) -> None: + if not self._engine.initialized: raise EngineError("tried to run command, but engine is not initialized") - def start(self, engine: ProtocolT) -> None: + def start(self) -> None: raise NotImplementedError - def line_received(self, engine: ProtocolT, line: str) -> None: + def line_received(self, line: str) -> None: pass - def engine_terminated(self, engine: ProtocolT, exc: Exception) -> None: - self._handle_exception(engine, exc) + def engine_terminated(self, exc: Exception) -> None: + self._handle_exception(exc) def __repr__(self) -> str: return "<{} at {:#x} (state={}, result={}, finished={}>".format(type(self).__name__, id(self), self.state, self.result, self.finished) @@ -1307,26 +1312,33 @@ def __init__(self) -> None: self.ponderhit = False async def initialize(self) -> None: - class UciInitializeCommand(BaseCommand[UciProtocol, None]): - def check_initialized(self, engine: UciProtocol) -> None: - if engine.initialized: + class UciInitializeCommand(BaseCommand[None]): + def __init__(self, engine: UciProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def check_initialized(self) -> None: + if self.engine.initialized: raise EngineError("engine already initialized") - def start(self, engine: UciProtocol) -> None: - engine.send_line("uci") + @typing.override + def start(self) -> None: + self.engine.send_line("uci") - def line_received(self, engine: UciProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: token, remaining = _next_token(line) if line.strip() == "uciok" and not self.result.done(): - engine.initialized = True + self.engine.initialized = True self.result.set_result(None) self.set_finished() elif token == "option": - self._option(engine, remaining) + self._option(remaining) elif token == "id": - self._id(engine, remaining) + self._id(remaining) - def _option(self, engine: UciProtocol, arg: str) -> None: + def _option(self, arg: str) -> None: current_parameter = None option_parts: dict[str, str] = {k: "" for k in ["name", "type", "default", "min", "max"]} var = [] @@ -1357,16 +1369,16 @@ def parse_min_max_value(option_parts: dict[str, str], which: Literal["min", "max without_default = Option(name, type, None, min, max, var) option = Option(without_default.name, without_default.type, without_default.parse(default), min, max, var) - engine.options[option.name] = option + self.engine.options[option.name] = option if option.default is not None: - engine.config[option.name] = option.default + self.engine.config[option.name] = option.default if option.default is not None and not option.is_managed() and option.name.lower() != "uci_analysemode": - engine.target_config[option.name] = option.default + self.engine.target_config[option.name] = option.default - def _id(self, engine: UciProtocol, arg: str) -> None: + def _id(self, arg: str) -> None: key, value = _next_token(arg) - engine.id[key] = value.strip() + self.engine.id[key] = value.strip() return await self.communicate(UciInitializeCommand) @@ -1395,16 +1407,21 @@ def debug(self, on: bool = True) -> None: self.send_line("debug off") async def ping(self) -> None: - class UciPingCommand(BaseCommand[UciProtocol, None]): - def start(self, engine: UciProtocol) -> None: - engine._isready() + class UciPingCommand(BaseCommand[None]): + def __init__(self, engine: UciProtocol) -> None: + super().__init__(engine) + self.engine = engine - def line_received(self, engine: UciProtocol, line: str) -> None: + def start(self) -> None: + self.engine._isready() + + @typing.override + def line_received(self, line: str) -> None: if line.strip() == "readyok": self.result.set_result(None) self.set_finished() else: - LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + LOGGER.warning("%s: Unexpected engine output: %r", self.engine, line) return await self.communicate(UciPingCommand) @@ -1438,10 +1455,14 @@ def _configure(self, options: ConfigMapping) -> None: self._setoption(name, value) async def configure(self, options: ConfigMapping) -> None: - class UciConfigureCommand(BaseCommand[UciProtocol, None]): - def start(self, engine: UciProtocol) -> None: - engine._configure(options) - engine.target_config.update({name: value for name, value in options.items() if value is not None}) + class UciConfigureCommand(BaseCommand[None]): + def __init__(self, engine: UciProtocol): + super().__init__(engine) + self.engine = engine + + def start(self) -> None: + self.engine._configure(options) + self.engine.target_config.update({name: value for name, value in options.items() if value is not None}) self.result.set_result(None) self.set_finished() @@ -1541,77 +1562,82 @@ async def play(self, board: chess.Board, limit: Limit, *, game: object = None, i new_options[name] = value new_options.update(self._opponent_configuration(opponent=opponent)) - class UciPlayCommand(BaseCommand[UciProtocol, PlayResult]): + engine = self + + class UciPlayCommand(BaseCommand[PlayResult]): def __init__(self, engine: UciProtocol): super().__init__(engine) + self.engine = engine # May ponderhit only in the same game and with unchanged target # options. The managed options UCI_AnalyseMode, Ponder, and # MultiPV never change between pondering play commands. engine.may_ponderhit = board if ponder and not engine.first_game and game == engine.game and not engine._changed_options(new_options) else None - def start(self, engine: UciProtocol) -> None: + @typing.override + def start(self) -> None: self.info: InfoDict = {} self.pondering: Optional[chess.Board] = None self.sent_isready = False self.start_time = time.perf_counter() - if engine.ponderhit: - engine.ponderhit = False - engine.send_line("ponderhit") + if self.engine.ponderhit: + self.engine.ponderhit = False + self.engine.send_line("ponderhit") return - if "UCI_AnalyseMode" in engine.options and "UCI_AnalyseMode" not in engine.target_config and all(name.lower() != "uci_analysemode" for name in new_options): - engine._setoption("UCI_AnalyseMode", False) - if "Ponder" in engine.options: - engine._setoption("Ponder", ponder) - if "MultiPV" in engine.options: - engine._setoption("MultiPV", engine.options["MultiPV"].default) + if "UCI_AnalyseMode" in self.engine.options and "UCI_AnalyseMode" not in self.engine.target_config and all(name.lower() != "uci_analysemode" for name in new_options): + self.engine._setoption("UCI_AnalyseMode", False) + if "Ponder" in self.engine.options: + self.engine._setoption("Ponder", ponder) + if "MultiPV" in self.engine.options: + self.engine._setoption("MultiPV", self.engine.options["MultiPV"].default) - new_opponent = new_options.get("UCI_Opponent") or engine.target_config.get("UCI_Opponent") - opponent_changed = new_opponent != engine.config.get("UCI_Opponent") - engine._configure(new_options) + new_opponent = new_options.get("UCI_Opponent") or self.engine.target_config.get("UCI_Opponent") + opponent_changed = new_opponent != self.engine.config.get("UCI_Opponent") + self.engine._configure(new_options) - if engine.first_game or engine.game != game or opponent_changed: - engine.game = game - engine._ucinewgame() + if self.engine.first_game or self.engine.game != game or opponent_changed: + self.engine.game = game + self.engine._ucinewgame() self.sent_isready = True - engine._isready() + self.engine._isready() else: - self._readyok(engine) + self._readyok() - def line_received(self, engine: UciProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token == "info": - self._info(engine, remaining) + self._info(remaining) elif token == "bestmove": - self._bestmove(engine, remaining) + self._bestmove(remaining) elif line.strip() == "readyok" and self.sent_isready: - self._readyok(engine) + self._readyok() else: - LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + LOGGER.warning("%s: Unexpected engine output: %r", self.engine, line) - def _readyok(self, engine: UciProtocol) -> None: + def _readyok(self) -> None: self.sent_isready = False engine._position(board) engine._go(limit, root_moves=root_moves) - def _info(self, engine: UciProtocol, arg: str) -> None: + def _info(self, arg: str) -> None: if not self.pondering: - self.info.update(_parse_uci_info(arg, engine.board, info)) + self.info.update(_parse_uci_info(arg, self.engine.board, info)) - def _bestmove(self, engine: UciProtocol, arg: str) -> None: + def _bestmove(self, arg: str) -> None: if self.pondering: self.pondering = None elif not self.result.cancelled(): - best = _parse_uci_bestmove(engine.board, arg) + best = _parse_uci_bestmove(self.engine.board, arg) self.result.set_result(PlayResult(best.move, best.ponder, self.info)) if ponder and best.move and best.ponder: self.pondering = board.copy() self.pondering.push(best.move) self.pondering.push(best.ponder) - engine._position(self.pondering) + self.engine._position(self.pondering) # Adjust clocks for pondering. time_used = time.perf_counter() - self.start_time @@ -1627,89 +1653,98 @@ def _bestmove(self, engine: UciProtocol, arg: str) -> None: if ponder_limit.remaining_moves: ponder_limit.remaining_moves -= 1 - engine._go(ponder_limit, ponder=True) + self.engine._go(ponder_limit, ponder=True) if not self.pondering: - self.end(engine) + self.end() - def end(self, engine: UciProtocol) -> None: + def end(self) -> None: engine.may_ponderhit = None self.set_finished() - def cancel(self, engine: UciProtocol) -> None: - if engine.may_ponderhit and self.pondering and engine.may_ponderhit.move_stack == self.pondering.move_stack and engine.may_ponderhit == self.pondering: - engine.ponderhit = True - self.end(engine) + @typing.override + def cancel(self) -> None: + if self.engine.may_ponderhit and self.pondering and self.engine.may_ponderhit.move_stack == self.pondering.move_stack and self.engine.may_ponderhit == self.pondering: + self.engine.ponderhit = True + self.end() else: - engine.send_line("stop") + self.engine.send_line("stop") - def engine_terminated(self, engine: UciProtocol, exc: Exception) -> None: + @typing.override + def engine_terminated(self, exc: Exception) -> None: # Allow terminating engine while pondering. if not self.result.done(): - super().engine_terminated(engine, exc) + super().engine_terminated(exc) return await self.communicate(UciPlayCommand) async def analysis(self, board: chess.Board, limit: Optional[Limit] = None, *, multipv: Optional[int] = None, game: object = None, info: Info = INFO_ALL, root_moves: Optional[Iterable[chess.Move]] = None, options: ConfigMapping = {}) -> AnalysisResult: - class UciAnalysisCommand(BaseCommand[UciProtocol, AnalysisResult]): - def start(self, engine: UciProtocol) -> None: - self.analysis = AnalysisResult(stop=lambda: self.cancel(engine)) + class UciAnalysisCommand(BaseCommand[AnalysisResult]): + def __init__(self, engine: UciProtocol): + super().__init__(engine) + self.engine = engine + + def start(self) -> None: + self.analysis = AnalysisResult(stop=lambda: self.cancel()) self.sent_isready = False - if "Ponder" in engine.options: - engine._setoption("Ponder", False) - if "UCI_AnalyseMode" in engine.options and "UCI_AnalyseMode" not in engine.target_config and all(name.lower() != "uci_analysemode" for name in options): - engine._setoption("UCI_AnalyseMode", True) - if "MultiPV" in engine.options or (multipv and multipv > 1): - engine._setoption("MultiPV", 1 if multipv is None else multipv) + if "Ponder" in self.engine.options: + self.engine._setoption("Ponder", False) + if "UCI_AnalyseMode" in self.engine.options and "UCI_AnalyseMode" not in self.engine.target_config and all(name.lower() != "uci_analysemode" for name in options): + self.engine._setoption("UCI_AnalyseMode", True) + if "MultiPV" in self.engine.options or (multipv and multipv > 1): + self.engine._setoption("MultiPV", 1 if multipv is None else multipv) - engine._configure(options) + self.engine._configure(options) - if engine.first_game or engine.game != game: - engine.game = game - engine._ucinewgame() + if self.engine.first_game or self.engine.game != game: + self.engine.game = game + self.engine._ucinewgame() self.sent_isready = True - engine._isready() + self.engine._isready() else: - self._readyok(engine) + self._readyok() - def line_received(self, engine: UciProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token == "info": - self._info(engine, remaining) + self._info(remaining) elif token == "bestmove": - self._bestmove(engine, remaining) + self._bestmove(remaining) elif line.strip() == "readyok" and self.sent_isready: - self._readyok(engine) + self._readyok() else: - LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + LOGGER.warning("%s: Unexpected engine output: %r", self.engine, line) - def _readyok(self, engine: UciProtocol) -> None: + def _readyok(self) -> None: self.sent_isready = False - engine._position(board) + self.engine._position(board) if limit: - engine._go(limit, root_moves=root_moves) + self.engine._go(limit, root_moves=root_moves) else: - engine._go(Limit(), root_moves=root_moves, infinite=True) + self.engine._go(Limit(), root_moves=root_moves, infinite=True) self.result.set_result(self.analysis) - def _info(self, engine: UciProtocol, arg: str) -> None: - self.analysis.post(_parse_uci_info(arg, engine.board, info)) + def _info(self, arg: str) -> None: + self.analysis.post(_parse_uci_info(arg, self.engine.board, info)) - def _bestmove(self, engine: UciProtocol, arg: str) -> None: + def _bestmove(self, arg: str) -> None: if not self.result.done(): raise EngineError("was not searching, but engine sent bestmove") - best = _parse_uci_bestmove(engine.board, arg) + best = _parse_uci_bestmove(self.engine.board, arg) self.set_finished() self.analysis.set_finished(best) - def cancel(self, engine: UciProtocol) -> None: - engine.send_line("stop") + @typing.override + def cancel(self) -> None: + self.engine.send_line("stop") - def engine_terminated(self, engine: UciProtocol, exc: Exception) -> None: - LOGGER.debug("%s: Closing analysis because engine has been terminated (error: %s)", engine, exc) + @typing.override + def engine_terminated(self, exc: Exception) -> None: + LOGGER.debug("%s: Closing analysis because engine has been terminated (error: %s)", self.engine, exc) self.analysis.set_exception(exc) return await self.communicate(UciAnalysisCommand) @@ -1938,89 +1973,96 @@ def __init__(self) -> None: self.first_game = True async def initialize(self) -> None: - class XBoardInitializeCommand(BaseCommand[XBoardProtocol, None]): - def check_initialized(self, engine: XBoardProtocol) -> None: - if engine.initialized: + class XBoardInitializeCommand(BaseCommand[None]): + def __init__(self, engine: XBoardProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def check_initialized(self) -> None: + if self.engine.initialized: raise EngineError("engine already initialized") - def start(self, engine: XBoardProtocol) -> None: - engine.send_line("xboard") - engine.send_line("protover 2") - self.timeout_handle = engine.loop.call_later(2.0, lambda: self.timeout(engine)) + @typing.override + def start(self) -> None: + self.engine.send_line("xboard") + self.engine.send_line("protover 2") + self.timeout_handle = self.engine.loop.call_later(2.0, lambda: self.timeout()) - def timeout(self, engine: XBoardProtocol) -> None: - LOGGER.error("%s: Timeout during initialization", engine) - self.end(engine) + def timeout(self) -> None: + LOGGER.error("%s: Timeout during initialization", self.engine) + self.end() - def line_received(self, engine: XBoardProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token.startswith("#"): pass elif token == "feature": - self._feature(engine, remaining) + self._feature(remaining) elif XBOARD_ERROR_REGEX.match(line): raise EngineError(line) - def _feature(self, engine: XBoardProtocol, arg: str) -> None: + def _feature(self, arg: str) -> None: for feature in shlex.split(arg): key, value = feature.split("=", 1) if key == "option": option = _parse_xboard_option(value) if option.name not in ["random", "computer", "cores", "memory"]: - engine.options[option.name] = option + self.engine.options[option.name] = option else: try: - engine.features[key] = int(value) + self.engine.features[key] = int(value) except ValueError: - engine.features[key] = value + self.engine.features[key] = value - if "done" in engine.features: + if "done" in self.engine.features: self.timeout_handle.cancel() - if engine.features.get("done"): - self.end(engine) + if self.engine.features.get("done"): + self.end() - def end(self, engine: XBoardProtocol) -> None: - if not engine.features.get("ping", 0): + def end(self) -> None: + if not self.engine.features.get("ping", 0): self.result.set_exception(EngineError("xboard engine did not declare required feature: ping")) self.set_finished() return - if not engine.features.get("setboard", 0): + if not self.engine.features.get("setboard", 0): self.result.set_exception(EngineError("xboard engine did not declare required feature: setboard")) self.set_finished() return - if not engine.features.get("reuse", 1): - LOGGER.warning("%s: Rejecting feature reuse=0", engine) - engine.send_line("rejected reuse") - if not engine.features.get("sigterm", 1): - LOGGER.warning("%s: Rejecting feature sigterm=0", engine) - engine.send_line("rejected sigterm") - if engine.features.get("san", 0): - LOGGER.warning("%s: Rejecting feature san=1", engine) - engine.send_line("rejected san") - - if "myname" in engine.features: - engine.id["name"] = str(engine.features["myname"]) - - if engine.features.get("memory", 0): - engine.options["memory"] = Option("memory", "spin", 16, 1, None, None) - engine.send_line("accepted memory") - if engine.features.get("smp", 0): - engine.options["cores"] = Option("cores", "spin", 1, 1, None, None) - engine.send_line("accepted smp") - if engine.features.get("egt"): - for egt in str(engine.features["egt"]).split(","): + if not self.engine.features.get("reuse", 1): + LOGGER.warning("%s: Rejecting feature reuse=0", self.engine) + self.engine.send_line("rejected reuse") + if not self.engine.features.get("sigterm", 1): + LOGGER.warning("%s: Rejecting feature sigterm=0", self.engine) + self.engine.send_line("rejected sigterm") + if self.engine.features.get("san", 0): + LOGGER.warning("%s: Rejecting feature san=1", self.engine) + self.engine.send_line("rejected san") + + if "myname" in self.engine.features: + self.engine.id["name"] = str(self.engine.features["myname"]) + + if self.engine.features.get("memory", 0): + self.engine.options["memory"] = Option("memory", "spin", 16, 1, None, None) + self.engine.send_line("accepted memory") + if self.engine.features.get("smp", 0): + self.engine.options["cores"] = Option("cores", "spin", 1, 1, None, None) + self.engine.send_line("accepted smp") + if self.engine.features.get("egt"): + for egt in str(self.engine.features["egt"]).split(","): name = f"egtpath {egt}" - engine.options[name] = Option(name, "path", None, None, None, None) - engine.send_line("accepted egt") + self.engine.options[name] = Option(name, "path", None, None, None, None) + self.engine.send_line("accepted egt") - for option in engine.options.values(): + for option in self.engine.options.values(): if option.default is not None: - engine.config[option.name] = option.default + self.engine.config[option.name] = option.default if option.default is not None and not option.is_managed(): - engine.target_config[option.name] = option.default + self.engine.target_config[option.name] = option.default - engine.initialized = True + self.engine.initialized = True self.result.set_result(None) self.set_finished() @@ -2105,18 +2147,24 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponen self.board.push(move) async def ping(self) -> None: - class XBoardPingCommand(BaseCommand[XBoardProtocol, None]): - def start(self, engine: XBoardProtocol) -> None: + class XBoardPingCommand(BaseCommand[None]): + def __init__(self, engine: XBoardProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def start(self) -> None: n = id(self) & 0xffff self.pong = f"pong {n}" - engine._ping(n) + self.engine._ping(n) - def line_received(self, engine: XBoardProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: if line == self.pong: self.result.set_result(None) self.set_finished() elif not line.startswith("#"): - LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + LOGGER.warning("%s: Unexpected engine output: %r", self.engine, line) elif XBOARD_ERROR_REGEX.match(line): raise EngineError(line) @@ -2126,54 +2174,60 @@ async def play(self, board: chess.Board, limit: Limit, *, game: object = None, i if root_moves is not None: raise EngineError("play with root_moves, but xboard supports 'include' only in analysis mode") - class XBoardPlayCommand(BaseCommand[XBoardProtocol, PlayResult]): - def start(self, engine: XBoardProtocol) -> None: + class XBoardPlayCommand(BaseCommand[PlayResult]): + def __init__(self, engine: XBoardProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def start(self) -> None: self.play_result = PlayResult(None, None) self.stopped = False self.pong_after_move: Optional[str] = None self.pong_after_ponder: Optional[str] = None # Set game, position and configure. - engine._new(board, game, options, opponent) + self.engine._new(board, game, options, opponent) # Limit or time control. clock = limit.white_clock if board.turn else limit.black_clock increment = limit.white_inc if board.turn else limit.black_inc - if limit.clock_id is None or limit.clock_id != engine.clock_id: - self._send_time_control(engine, clock, increment) - engine.clock_id = limit.clock_id + if limit.clock_id is None or limit.clock_id != self.engine.clock_id: + self._send_time_control(clock, increment) + self.engine.clock_id = limit.clock_id if limit.nodes is not None: if limit.time is not None or limit.white_clock is not None or limit.black_clock is not None or increment is not None: raise EngineError("xboard does not support mixing node limits with time limits") - if "nps" not in engine.features: + if "nps" not in self.engine.features: LOGGER.warning("%s: Engine did not explicitly declare support for node limits (feature nps=?)") - elif not engine.features["nps"]: + elif not self.engine.features["nps"]: raise EngineError("xboard engine does not support node limits (feature nps=0)") - engine.send_line("nps 1") - engine.send_line(f"st {max(1, int(limit.nodes))}") + self.engine.send_line("nps 1") + self.engine.send_line(f"st {max(1, int(limit.nodes))}") if limit.depth is not None: - engine.send_line(f"sd {max(1, int(limit.depth))}") + self.engine.send_line(f"sd {max(1, int(limit.depth))}") if limit.white_clock is not None: - engine.send_line("{} {}".format("time" if board.turn else "otim", max(1, round(limit.white_clock * 100)))) + self.engine.send_line("{} {}".format("time" if board.turn else "otim", max(1, round(limit.white_clock * 100)))) if limit.black_clock is not None: - engine.send_line("{} {}".format("otim" if board.turn else "time", max(1, round(limit.black_clock * 100)))) + self.engine.send_line("{} {}".format("otim" if board.turn else "time", max(1, round(limit.black_clock * 100)))) - if draw_offered and engine.features.get("draw", 1): - engine.send_line("draw") + if draw_offered and self.engine.features.get("draw", 1): + self.engine.send_line("draw") # Start thinking. - engine.send_line("post" if info else "nopost") - engine.send_line("hard" if ponder else "easy") - engine.send_line("go") + self.engine.send_line("post" if info else "nopost") + self.engine.send_line("hard" if ponder else "easy") + self.engine.send_line("go") - def line_received(self, engine: XBoardProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token == "move": - self._move(engine, remaining.strip()) + self._move(remaining.strip()) elif token == "Hint:": - self._hint(engine, remaining.strip()) + self._hint(remaining.strip()) elif token == "pong": pong_line = f"{token} {remaining.strip()}" if pong_line == self.pong_after_move: @@ -2188,84 +2242,86 @@ def line_received(self, engine: XBoardProtocol, line: str) -> None: elif f"{token} {remaining.strip()}" == "offer draw": if not self.result.done(): self.play_result.draw_offered = True - self._ping_after_move(engine) + self._ping_after_move() elif line.strip() == "resign": if not self.result.done(): self.play_result.resigned = True - self._ping_after_move(engine) + self._ping_after_move() elif token in ["1-0", "0-1", "1/2-1/2"]: if "resign" in line and not self.result.done(): self.play_result.resigned = True - self._ping_after_move(engine) + self._ping_after_move() elif token.startswith("#"): pass elif XBOARD_ERROR_REGEX.match(line): - engine.first_game = True # Board state might no longer be in sync + self.engine.first_game = True # Board state might no longer be in sync raise EngineError(line) elif len(line.split()) >= 4 and line.lstrip()[0].isdigit(): - self._post(engine, line) + self._post(line) else: - LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + LOGGER.warning("%s: Unexpected engine output: %r", self.engine, line) - def _send_time_control(self, engine: XBoardProtocol, clock: Optional[float], increment: Optional[float]) -> None: + def _send_time_control(self, clock: Optional[float], increment: Optional[float]) -> None: if limit.remaining_moves or clock is not None or increment is not None: base_mins, base_secs = divmod(int(clock or 0), 60) - engine.send_line(f"level {limit.remaining_moves or 0} {base_mins}:{base_secs:02d} {increment or 0}") + self.engine.send_line(f"level {limit.remaining_moves or 0} {base_mins}:{base_secs:02d} {increment or 0}") if limit.time is not None: - engine.send_line(f"st {max(0.01, limit.time)}") + self.engine.send_line(f"st {max(0.01, limit.time)}") - def _post(self, engine: XBoardProtocol, line: str) -> None: + def _post(self, line: str) -> None: if not self.result.done(): - self.play_result.info = _parse_xboard_post(line, engine.board, info) + self.play_result.info = _parse_xboard_post(line, self.engine.board, info) - def _move(self, engine: XBoardProtocol, arg: str) -> None: + def _move(self, arg: str) -> None: if not self.result.done() and self.play_result.move is None: try: - self.play_result.move = engine.board.push_xboard(arg) + self.play_result.move = self.engine.board.push_xboard(arg) except ValueError as err: self.result.set_exception(EngineError(err)) else: - self._ping_after_move(engine) + self._ping_after_move() else: try: - engine.board.push_xboard(arg) + self.engine.board.push_xboard(arg) except ValueError: LOGGER.exception("Exception playing unexpected move") - def _hint(self, engine: XBoardProtocol, arg: str) -> None: + def _hint(self, arg: str) -> None: if not self.result.done() and self.play_result.move is not None and self.play_result.ponder is None: try: - self.play_result.ponder = engine.board.parse_xboard(arg) + self.play_result.ponder = self.engine.board.parse_xboard(arg) except ValueError: LOGGER.exception("Exception parsing hint") else: LOGGER.warning("Unexpected hint: %r", arg) - def _ping_after_move(self, engine: XBoardProtocol) -> None: + def _ping_after_move(self) -> None: if self.pong_after_move is None: n = id(self) & 0xffff self.pong_after_move = f"pong {n}" - engine._ping(n) + self.engine._ping(n) - def cancel(self, engine: XBoardProtocol) -> None: + @typing.override + def cancel(self) -> None: if self.stopped: return self.stopped = True if self.result.cancelled(): - engine.send_line("?") + self.engine.send_line("?") if ponder: - engine.send_line("easy") + self.engine.send_line("easy") n = (id(self) + 1) & 0xffff self.pong_after_ponder = f"pong {n}" - engine._ping(n) + self.engine._ping(n) - def engine_terminated(self, engine: XBoardProtocol, exc: Exception) -> None: + @typing.override + def engine_terminated(self, exc: Exception) -> None: # Allow terminating engine while pondering. if not self.result.done(): - super().engine_terminated(engine, exc) + super().engine_terminated(exc) return await self.communicate(XBoardPlayCommand) @@ -2276,49 +2332,55 @@ async def analysis(self, board: chess.Board, limit: Optional[Limit] = None, *, m if limit is not None and (limit.white_clock is not None or limit.black_clock is not None): raise EngineError("xboard analysis does not support clock limits") - class XBoardAnalysisCommand(BaseCommand[XBoardProtocol, AnalysisResult]): - def start(self, engine: XBoardProtocol) -> None: + class XBoardAnalysisCommand(BaseCommand[AnalysisResult]): + def __init__(self, engine: XBoardProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def start(self) -> None: self.stopped = False self.best_move: Optional[chess.Move] = None - self.analysis = AnalysisResult(stop=lambda: self.cancel(engine)) + self.analysis = AnalysisResult(stop=lambda: self.cancel()) self.final_pong: Optional[str] = None - engine._new(board, game, options) + self.engine._new(board, game, options) if root_moves is not None: - if not engine.features.get("exclude", 0): + if not self.engine.features.get("exclude", 0): raise EngineError("xboard engine does not support root_moves (feature exclude=0)") - engine.send_line("exclude all") + self.engine.send_line("exclude all") for move in root_moves: - engine.send_line(f"include {engine.board.xboard(move)}") + self.engine.send_line(f"include {self.engine.board.xboard(move)}") - engine.send_line("post") - engine.send_line("analyze") + self.engine.send_line("post") + self.engine.send_line("analyze") self.result.set_result(self.analysis) if limit is not None and limit.time is not None: - self.time_limit_handle: Optional[asyncio.Handle] = engine.loop.call_later(limit.time, lambda: self.cancel(engine)) + self.time_limit_handle: Optional[asyncio.Handle] = self.engine.loop.call_later(limit.time, lambda: self.cancel()) else: self.time_limit_handle = None - def line_received(self, engine: XBoardProtocol, line: str) -> None: + @typing.override + def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token.startswith("#"): pass elif len(line.split()) >= 4 and line.lstrip()[0].isdigit(): - self._post(engine, line) + self._post(line) elif f"{token} {remaining.strip()}" == self.final_pong: - self.end(engine) + self.end() elif XBOARD_ERROR_REGEX.match(line): - engine.first_game = True # Board state might no longer be in sync + self.engine.first_game = True # Board state might no longer be in sync raise EngineError(line) else: - LOGGER.warning("%s: Unexpected engine output: %r", engine, line) + LOGGER.warning("%s: Unexpected engine output: %r", self.engine, line) - def _post(self, engine: XBoardProtocol, line: str) -> None: - post_info = _parse_xboard_post(line, engine.board, info) + def _post(self, line: str) -> None: + post_info = _parse_xboard_post(line, self.engine.board, info) self.analysis.post(post_info) pv = post_info.get("pv") @@ -2327,36 +2389,38 @@ def _post(self, engine: XBoardProtocol, line: str) -> None: if limit is not None: if limit.time is not None and post_info.get("time", 0) >= limit.time: - self.cancel(engine) + self.cancel() elif limit.nodes is not None and post_info.get("nodes", 0) >= limit.nodes: - self.cancel(engine) + self.cancel() elif limit.depth is not None and post_info.get("depth", 0) >= limit.depth: - self.cancel(engine) + self.cancel() elif limit.mate is not None and "score" in post_info: if post_info["score"].relative >= Mate(limit.mate): - self.cancel(engine) + self.cancel() - def end(self, engine: XBoardProtocol) -> None: + def end(self) -> None: if self.time_limit_handle: self.time_limit_handle.cancel() self.set_finished() self.analysis.set_finished(BestMove(self.best_move, None)) - def cancel(self, engine: XBoardProtocol) -> None: + @typing.override + def cancel(self) -> None: if self.stopped: return self.stopped = True - engine.send_line(".") - engine.send_line("exit") + self.engine.send_line(".") + self.engine.send_line("exit") n = id(self) & 0xffff self.final_pong = f"pong {n}" - engine._ping(n) + self.engine._ping(n) - def engine_terminated(self, engine: XBoardProtocol, exc: Exception) -> None: - LOGGER.debug("%s: Closing analysis because engine has been terminated (error: %s)", engine, exc) + @typing.override + def engine_terminated(self, exc: Exception) -> None: + LOGGER.debug("%s: Closing analysis because engine has been terminated (error: %s)", self.engine, exc) if self.time_limit_handle: self.time_limit_handle.cancel() @@ -2397,10 +2461,15 @@ def _configure(self, options: ConfigMapping) -> None: self._setoption(name, value) async def configure(self, options: ConfigMapping) -> None: - class XBoardConfigureCommand(BaseCommand[XBoardProtocol, None]): - def start(self, engine: XBoardProtocol) -> None: - engine._configure(options) - engine.target_config.update({name: value for name, value in options.items() if value is not None}) + class XBoardConfigureCommand(BaseCommand[None]): + def __init__(self, engine: XBoardProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def start(self) -> None: + self.engine._configure(options) + self.engine.target_config.update({name: value for name, value in options.items() if value is not None}) self.result.set_result(None) self.set_finished() @@ -2423,12 +2492,17 @@ async def send_opponent_information(self, *, opponent: Optional[Opponent] = None return await self.configure(self._opponent_configuration(opponent=opponent, engine_rating=engine_rating)) async def send_game_result(self, board: chess.Board, winner: Optional[Color] = None, game_ending: Optional[str] = None, game_complete: bool = True) -> None: - class XBoardGameResultCommand(BaseCommand[XBoardProtocol, None]): - def start(self, engine: XBoardProtocol) -> None: + class XBoardGameResultCommand(BaseCommand[None]): + def __init__(self, engine: XBoardProtocol): + super().__init__(engine) + self.engine = engine + + @typing.override + def start(self) -> None: if game_ending and any(c in game_ending for c in "{}\n\r"): raise EngineError(f"invalid line break or curly braces in game ending message: {game_ending!r}") - engine._new(board, engine.game, {}) # Send final moves to engine. + self.engine._new(board, self.engine.game, {}) # Send final moves to engine. outcome = board.outcome(claim_draw=True) @@ -2451,7 +2525,7 @@ def start(self, engine: XBoardProtocol) -> None: ending = "" ending_text = f"{{{ending}}}" if ending else "" - engine.send_line(f"result {result} {ending_text}".strip()) + self.engine.send_line(f"result {result} {ending_text}".strip()) self.result.set_result(None) self.set_finished() @@ -2845,7 +2919,7 @@ def id(self) -> Mapping[str, str]: future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) return future.result() - def communicate(self, command_factory: Callable[[Protocol], BaseCommand[Protocol, T]]) -> T: + def communicate(self, command_factory: Callable[[Protocol], BaseCommand[T]]) -> T: with self._not_shut_down(): coro = self.protocol.communicate(command_factory) future = asyncio.run_coroutine_threadsafe(coro, self.protocol.loop) From 5d8e82da82156f5eae2d15f07e2c24d800c87a41 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 16:05:29 +0200 Subject: [PATCH 190/250] Let variant boards manage their own stack --- chess/__init__.py | 9 +++---- chess/variant.py | 66 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index a90df9ef6..b82f8559f 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -1542,7 +1542,7 @@ def from_chess960_pos(cls: Type[BaseBoardT], scharnagl: int) -> BaseBoardT: BoardT = TypeVar("BoardT", bound="Board") -class _BoardState(Generic[BoardT]): +class _BoardState: def __init__(self, board: BoardT) -> None: self.pawns = board.pawns @@ -1701,7 +1701,7 @@ def __init__(self: BoardT, fen: Optional[str] = STARTING_FEN, *, chess960: bool self.ep_square = None self.move_stack = [] - self._stack: List[_BoardState[BoardT]] = [] + self._stack: List[_BoardState] = [] if fen is None: self.clear() @@ -2304,9 +2304,6 @@ def is_repetition(self, count: int = 3) -> bool: return False - def _board_state(self: BoardT) -> _BoardState[BoardT]: - return _BoardState(self) - def _push_capture(self, move: Move, capture_square: Square, piece_type: PieceType, was_promoted: bool) -> None: pass @@ -2335,7 +2332,7 @@ def push(self: BoardT, move: Move) -> None: """ # Push move and remember board state. move = self._to_chess960(move) - board_state = self._board_state() + board_state = _BoardState(self) self.castling_rights = self.clean_castling_rights() # Before pushing stack self.move_stack.append(self._from_chess960(self.chess960, move.from_square, move.to_square, move.promotion, move.drop)) self._stack.append(board_state) diff --git a/chess/variant.py b/chess/variant.py index 6160696a2..119a0402c 100644 --- a/chess/variant.py +++ b/chess/variant.py @@ -673,14 +673,12 @@ def status(self) -> chess.Status: ThreeCheckBoardT = TypeVar("ThreeCheckBoardT", bound="ThreeCheckBoard") -class _ThreeCheckBoardState(Generic[ThreeCheckBoardT], chess._BoardState[ThreeCheckBoardT]): - def __init__(self, board: ThreeCheckBoardT) -> None: - super().__init__(board) +class _ThreeCheckBoardState: + def __init__(self, board: ThreeCheckBoard) -> None: self.remaining_checks_w = board.remaining_checks[chess.WHITE] self.remaining_checks_b = board.remaining_checks[chess.BLACK] - def restore(self, board: ThreeCheckBoardT) -> None: - super().restore(board) + def restore(self, board: ThreeCheckBoard) -> None: board.remaining_checks[chess.WHITE] = self.remaining_checks_w board.remaining_checks[chess.BLACK] = self.remaining_checks_b @@ -698,8 +696,13 @@ class ThreeCheckBoard(chess.Board): def __init__(self, fen: Optional[str] = starting_fen, chess960: bool = False) -> None: self.remaining_checks = [3, 3] + self._three_check_stack: List[_ThreeCheckBoardState] = [] super().__init__(fen, chess960=chess960) + def clear_stack(self) -> None: + super().clear_stack() + self._three_check_stack.clear() + def reset_board(self) -> None: super().reset_board() self.remaining_checks[chess.WHITE] = 3 @@ -710,14 +713,17 @@ def clear_board(self) -> None: self.remaining_checks[chess.WHITE] = 3 self.remaining_checks[chess.BLACK] = 3 - def _board_state(self: ThreeCheckBoardT) -> _ThreeCheckBoardState[ThreeCheckBoardT]: - return _ThreeCheckBoardState(self) - def push(self, move: chess.Move) -> None: + self._three_check_stack.append(_ThreeCheckBoardState(self)) super().push(move) if self.is_check(): self.remaining_checks[not self.turn] -= 1 + def pop(self) -> chess.Move: + move = super().pop() + self._three_check_stack.pop().restore(self) + return move + def has_insufficient_material(self, color: chess.Color) -> bool: # Any remaining piece can give check. return not (self.occupied_co[color] & ~self.kings) @@ -792,8 +798,19 @@ def _transposition_key(self) -> Hashable: def copy(self: ThreeCheckBoardT, stack: Union[bool, int] = True) -> ThreeCheckBoardT: board = super().copy(stack=stack) board.remaining_checks = self.remaining_checks.copy() + if stack: + stack = len(self.move_stack) if stack is True else stack + board._three_check_stack = self._three_check_stack[-stack:] return board + def root(self: ThreeCheckBoardT) -> ThreeCheckBoardT: + if self._three_check_stack: + board = super().root() + self._three_check_stack[0].restore(board) + return board + else: + return self.copy(stack=False) + def mirror(self: ThreeCheckBoardT) -> ThreeCheckBoardT: board = super().mirror() board.remaining_checks[chess.WHITE] = self.remaining_checks[chess.BLACK] @@ -803,14 +820,12 @@ def mirror(self: ThreeCheckBoardT) -> ThreeCheckBoardT: CrazyhouseBoardT = TypeVar("CrazyhouseBoardT", bound="CrazyhouseBoard") -class _CrazyhouseBoardState(Generic[CrazyhouseBoardT], chess._BoardState[CrazyhouseBoardT]): - def __init__(self, board: CrazyhouseBoardT) -> None: - super().__init__(board) +class _CrazyhouseBoardState: + def __init__(self, board: CrazyhouseBoard) -> None: self.pockets_w = board.pockets[chess.WHITE].copy() self.pockets_b = board.pockets[chess.BLACK].copy() - def restore(self, board: CrazyhouseBoardT) -> None: - super().restore(board) + def restore(self, board: CrazyhouseBoard) -> None: board.pockets[chess.WHITE] = self.pockets_w board.pockets[chess.BLACK] = self.pockets_b @@ -870,8 +885,13 @@ class CrazyhouseBoard(chess.Board): def __init__(self, fen: Optional[str] = starting_fen, chess960: bool = False) -> None: self.pockets = [CrazyhousePocket(), CrazyhousePocket()] + self._crazyhouse_stack: List[_CrazyhouseBoardState] = [] super().__init__(fen, chess960=chess960) + def clear_stack(self) -> None: + super().clear_stack() + self._crazyhouse_stack.clear() + def reset_board(self) -> None: super().reset_board() self.pockets[chess.WHITE].reset() @@ -882,10 +902,8 @@ def clear_board(self) -> None: self.pockets[chess.WHITE].reset() self.pockets[chess.BLACK].reset() - def _board_state(self: CrazyhouseBoardT) -> _CrazyhouseBoardState[CrazyhouseBoardT]: - return _CrazyhouseBoardState(self) - def push(self, move: chess.Move) -> None: + self._crazyhouse_stack.append(_CrazyhouseBoardState(self)) super().push(move) if move.drop: self.pockets[not self.turn].remove(move.drop) @@ -896,6 +914,11 @@ def _push_capture(self, move: chess.Move, capture_square: chess.Square, piece_ty else: self.pockets[self.turn].add(piece_type) + def pop(self) -> chess.Move: + move = super().pop() + self._crazyhouse_stack.pop().restore(self) + return move + def _is_halfmoves(self, n: int) -> bool: # No draw by 50-move rule or 75-move rule. return False @@ -1028,8 +1051,19 @@ def copy(self: CrazyhouseBoardT, stack: Union[bool, int] = True) -> CrazyhouseBo board = super().copy(stack=stack) board.pockets[chess.WHITE] = self.pockets[chess.WHITE].copy() board.pockets[chess.BLACK] = self.pockets[chess.BLACK].copy() + if stack: + stack = len(self.move_stack) if stack is True else stack + board._crazyhouse_stack = self._crazyhouse_stack[-stack:] return board + def root(self: CrazyhouseBoardT) -> CrazyhouseBoardT: + if self._crazyhouse_stack: + board = super().root() + self._crazyhouse_stack[0].restore(board) + return board + else: + return self.copy(stack=False) + def mirror(self: CrazyhouseBoardT) -> CrazyhouseBoardT: board = super().mirror() board.pockets[chess.WHITE] = self.pockets[chess.BLACK].copy() From a652aaad5d22edd4cc078dba9214fb1d81789d7a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 16:13:51 +0200 Subject: [PATCH 191/250] Add fallback for override decorator --- chess/engine.py | 60 ++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index d1bbaaee1..f5fdff96a 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -24,6 +24,14 @@ from types import TracebackType from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypedDict, TypeVar, Union +try: + from typing import override +except: + # Before Python 3.12 + F = typing.TypeVar("F", bound=Callable[..., Any]) + def override(fn: F, /) -> F: + return fn + if typing.TYPE_CHECKING: from typing_extensions import Self @@ -1317,16 +1325,16 @@ def __init__(self, engine: UciProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def check_initialized(self) -> None: if self.engine.initialized: raise EngineError("engine already initialized") - @typing.override + @override def start(self) -> None: self.engine.send_line("uci") - @typing.override + @override def line_received(self, line: str) -> None: token, remaining = _next_token(line) if line.strip() == "uciok" and not self.result.done(): @@ -1415,7 +1423,7 @@ def __init__(self, engine: UciProtocol) -> None: def start(self) -> None: self.engine._isready() - @typing.override + @override def line_received(self, line: str) -> None: if line.strip() == "readyok": self.result.set_result(None) @@ -1574,7 +1582,7 @@ def __init__(self, engine: UciProtocol): # MultiPV never change between pondering play commands. engine.may_ponderhit = board if ponder and not engine.first_game and game == engine.game and not engine._changed_options(new_options) else None - @typing.override + @override def start(self) -> None: self.info: InfoDict = {} self.pondering: Optional[chess.Board] = None @@ -1605,7 +1613,7 @@ def start(self) -> None: else: self._readyok() - @typing.override + @override def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token == "info": @@ -1662,7 +1670,7 @@ def end(self) -> None: engine.may_ponderhit = None self.set_finished() - @typing.override + @override def cancel(self) -> None: if self.engine.may_ponderhit and self.pondering and self.engine.may_ponderhit.move_stack == self.pondering.move_stack and self.engine.may_ponderhit == self.pondering: self.engine.ponderhit = True @@ -1670,7 +1678,7 @@ def cancel(self) -> None: else: self.engine.send_line("stop") - @typing.override + @override def engine_terminated(self, exc: Exception) -> None: # Allow terminating engine while pondering. if not self.result.done(): @@ -1705,7 +1713,7 @@ def start(self) -> None: else: self._readyok() - @typing.override + @override def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token == "info": @@ -1738,11 +1746,11 @@ def _bestmove(self, arg: str) -> None: self.set_finished() self.analysis.set_finished(best) - @typing.override + @override def cancel(self) -> None: self.engine.send_line("stop") - @typing.override + @override def engine_terminated(self, exc: Exception) -> None: LOGGER.debug("%s: Closing analysis because engine has been terminated (error: %s)", self.engine, exc) self.analysis.set_exception(exc) @@ -1978,12 +1986,12 @@ def __init__(self, engine: XBoardProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def check_initialized(self) -> None: if self.engine.initialized: raise EngineError("engine already initialized") - @typing.override + @override def start(self) -> None: self.engine.send_line("xboard") self.engine.send_line("protover 2") @@ -1993,7 +2001,7 @@ def timeout(self) -> None: LOGGER.error("%s: Timeout during initialization", self.engine) self.end() - @typing.override + @override def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token.startswith("#"): @@ -2152,13 +2160,13 @@ def __init__(self, engine: XBoardProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def start(self) -> None: n = id(self) & 0xffff self.pong = f"pong {n}" self.engine._ping(n) - @typing.override + @override def line_received(self, line: str) -> None: if line == self.pong: self.result.set_result(None) @@ -2179,7 +2187,7 @@ def __init__(self, engine: XBoardProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def start(self) -> None: self.play_result = PlayResult(None, None) self.stopped = False @@ -2221,7 +2229,7 @@ def start(self) -> None: self.engine.send_line("hard" if ponder else "easy") self.engine.send_line("go") - @typing.override + @override def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token == "move": @@ -2301,7 +2309,7 @@ def _ping_after_move(self) -> None: self.pong_after_move = f"pong {n}" self.engine._ping(n) - @typing.override + @override def cancel(self) -> None: if self.stopped: return @@ -2317,7 +2325,7 @@ def cancel(self) -> None: self.pong_after_ponder = f"pong {n}" self.engine._ping(n) - @typing.override + @override def engine_terminated(self, exc: Exception) -> None: # Allow terminating engine while pondering. if not self.result.done(): @@ -2337,7 +2345,7 @@ def __init__(self, engine: XBoardProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def start(self) -> None: self.stopped = False self.best_move: Optional[chess.Move] = None @@ -2364,7 +2372,7 @@ def start(self) -> None: else: self.time_limit_handle = None - @typing.override + @override def line_received(self, line: str) -> None: token, remaining = _next_token(line) if token.startswith("#"): @@ -2405,7 +2413,7 @@ def end(self) -> None: self.set_finished() self.analysis.set_finished(BestMove(self.best_move, None)) - @typing.override + @override def cancel(self) -> None: if self.stopped: return @@ -2418,7 +2426,7 @@ def cancel(self) -> None: self.final_pong = f"pong {n}" self.engine._ping(n) - @typing.override + @override def engine_terminated(self, exc: Exception) -> None: LOGGER.debug("%s: Closing analysis because engine has been terminated (error: %s)", self.engine, exc) @@ -2466,7 +2474,7 @@ def __init__(self, engine: XBoardProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def start(self) -> None: self.engine._configure(options) self.engine.target_config.update({name: value for name, value in options.items() if value is not None}) @@ -2497,7 +2505,7 @@ def __init__(self, engine: XBoardProtocol): super().__init__(engine) self.engine = engine - @typing.override + @override def start(self) -> None: if game_ending and any(c in game_ending for c in "{}\n\r"): raise EngineError(f"invalid line break or curly braces in game ending message: {game_ending!r}") From 7a59a3683f33682c0c2c9b359469c8b9876ece9e Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 17:02:12 +0200 Subject: [PATCH 192/250] Import override from typing_extensions --- chess/engine.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index f5fdff96a..347acf297 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -24,10 +24,9 @@ from types import TracebackType from typing import Any, Callable, Coroutine, Deque, Dict, Generator, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Optional, Tuple, Type, TypedDict, TypeVar, Union -try: - from typing import override -except: - # Before Python 3.12 +if typing.TYPE_CHECKING: + from typing_extensions import override +else: F = typing.TypeVar("F", bound=Callable[..., Any]) def override(fn: F, /) -> F: return fn From 571658baa358b97f3cb5104c3dfab33c6d962deb Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 17:25:03 +0200 Subject: [PATCH 193/250] Use typing_extensions.Self --- chess/__init__.py | 32 ++++++++++++++++---------------- chess/engine.py | 2 +- chess/pgn.py | 7 +++++-- chess/syzygy.py | 7 ++++--- chess/variant.py | 18 +++++++++++------- 5 files changed, 37 insertions(+), 29 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index b82f8559f..3553eee65 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -25,7 +25,7 @@ from typing import ClassVar, Callable, Counter, Dict, Generic, Hashable, Iterable, Iterator, List, Literal, Mapping, Optional, SupportsInt, Tuple, Type, TypeVar, Union if typing.TYPE_CHECKING: - from typing_extensions import TypeAlias + from typing_extensions import Self, TypeAlias EnPassantSpec = Literal["legal", "fen", "xfen"] @@ -1455,7 +1455,7 @@ def apply_transform(self, f: Callable[[Bitboard], Bitboard]) -> None: self.occupied = f(self.occupied) self.promoted = f(self.promoted) - def transform(self: BaseBoardT, f: Callable[[Bitboard], Bitboard]) -> BaseBoardT: + def transform(self, f: Callable[[Bitboard], Bitboard]) -> Self: """ Returns a transformed copy of the board (without move stack) by applying a bitboard transformation function. @@ -1473,11 +1473,11 @@ def transform(self: BaseBoardT, f: Callable[[Bitboard], Bitboard]) -> BaseBoardT board.apply_transform(f) return board - def apply_mirror(self: BaseBoardT) -> None: + def apply_mirror(self) -> None: self.apply_transform(flip_vertical) self.occupied_co[WHITE], self.occupied_co[BLACK] = self.occupied_co[BLACK], self.occupied_co[WHITE] - def mirror(self: BaseBoardT) -> BaseBoardT: + def mirror(self) -> Self: """ Returns a mirrored copy of the board (without move stack). @@ -1491,7 +1491,7 @@ def mirror(self: BaseBoardT) -> BaseBoardT: board.apply_mirror() return board - def copy(self: BaseBoardT) -> BaseBoardT: + def copy(self) -> Self: """Creates a copy of the board.""" board = type(self)(None) @@ -1509,10 +1509,10 @@ def copy(self: BaseBoardT) -> BaseBoardT: return board - def __copy__(self: BaseBoardT) -> BaseBoardT: + def __copy__(self) -> Self: return self.copy() - def __deepcopy__(self: BaseBoardT, memo: Dict[int, object]) -> BaseBoardT: + def __deepcopy__(self, memo: Dict[int, object]) -> Self: board = self.copy() memo[id(self)] = board return board @@ -1694,7 +1694,7 @@ class Board(BaseBoard): manipulation. """ - def __init__(self: BoardT, fen: Optional[str] = STARTING_FEN, *, chess960: bool = False) -> None: + def __init__(self, fen: Optional[str] = STARTING_FEN, *, chess960: bool = False) -> None: BaseBoard.__init__(self, None) self.chess960 = chess960 @@ -1786,7 +1786,7 @@ def clear_stack(self) -> None: self.move_stack.clear() self._stack.clear() - def root(self: BoardT) -> BoardT: + def root(self) -> Self: """Returns a copy of the root position.""" if self._stack: board = type(self)(None, chess960=self.chess960) @@ -2307,7 +2307,7 @@ def is_repetition(self, count: int = 3) -> bool: def _push_capture(self, move: Move, capture_square: Square, piece_type: PieceType, was_promoted: bool) -> None: pass - def push(self: BoardT, move: Move) -> None: + def push(self, move: Move) -> None: """ Updates the position with the given *move* and puts it onto the move stack. @@ -2428,7 +2428,7 @@ def push(self: BoardT, move: Move) -> None: # Swap turn. self.turn = not self.turn - def pop(self: BoardT) -> Move: + def pop(self) -> Move: """ Restores the previous position and returns the last move from the stack. @@ -2838,7 +2838,7 @@ def _validate_epd_opcode(self, opcode: str) -> None: if blacklisted in opcode: raise ValueError(f"invalid character {blacklisted!r} in epd opcode: {opcode!r}") - def _parse_epd_ops(self: BoardT, operation_part: str, make_board: Callable[[], BoardT]) -> Dict[str, Union[None, str, int, float, Move, List[Move]]]: + def _parse_epd_ops(self, operation_part: str, make_board: Callable[[], Self]) -> Dict[str, Union[None, str, int, float, Move, List[Move]]]: operations: Dict[str, Union[None, str, int, float, Move, List[Move]]] = {} state = "opcode" opcode = "" @@ -3831,16 +3831,16 @@ def apply_transform(self, f: Callable[[Bitboard], Bitboard]) -> None: self.ep_square = None if self.ep_square is None else msb(f(BB_SQUARES[self.ep_square])) self.castling_rights = f(self.castling_rights) - def transform(self: BoardT, f: Callable[[Bitboard], Bitboard]) -> BoardT: + def transform(self, f: Callable[[Bitboard], Bitboard]) -> Self: board = self.copy(stack=False) board.apply_transform(f) return board - def apply_mirror(self: BoardT) -> None: + def apply_mirror(self) -> None: super().apply_mirror() self.turn = not self.turn - def mirror(self: BoardT) -> BoardT: + def mirror(self) -> Self: """ Returns a mirrored copy of the board. @@ -3855,7 +3855,7 @@ def mirror(self: BoardT) -> BoardT: board.apply_mirror() return board - def copy(self: BoardT, *, stack: Union[bool, int] = True) -> BoardT: + def copy(self, *, stack: Union[bool, int] = True) -> Self: """ Creates a copy of the board. diff --git a/chess/engine.py b/chess/engine.py index 347acf297..59b843b8b 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -970,7 +970,7 @@ def pipe_data_received(self, fd: int, data: Union[bytes, str]) -> None: def error_line_received(self, line: str) -> None: LOGGER.warning("%s: stderr >> %s", self, line) - def _line_received(self: Protocol, line: str) -> None: + def _line_received(self, line: str) -> None: LOGGER.debug("%s: >> %s", self, line) self.line_received(line) diff --git a/chess/pgn.py b/chess/pgn.py index 0d0879ae0..83ddaf8f5 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -15,6 +15,9 @@ from typing import Any, Callable, Dict, Generic, Iterable, Iterator, List, Literal, Mapping, MutableMapping, Set, TextIO, Tuple, Type, TypeVar, Optional, Union from chess import Color, Square +if typing.TYPE_CHECKING: + from typing_extensions import Self + LOGGER = logging.getLogger(__name__) @@ -1014,10 +1017,10 @@ def __iter__(self) -> Iterator[str]: def __len__(self) -> int: return len(self._tag_roster) + len(self._others) - def copy(self: HeadersT) -> HeadersT: + def copy(self) -> Self: return type(self)(self) - def __copy__(self: HeadersT) -> HeadersT: + def __copy__(self) -> Self: return self.copy() def __repr__(self) -> str: diff --git a/chess/syzygy.py b/chess/syzygy.py index 8ba1cbca4..77a6eeded 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -14,6 +14,9 @@ from types import TracebackType from typing import Deque, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type, TypeVar, Union +if typing.TYPE_CHECKING: + from typing_extensions import Self + UINT64_BE = struct.Struct(">Q") UINT32 = struct.Struct(" None: self.data.close() self.data = None - def __enter__(self: TableT) -> TableT: + def __enter__(self) -> Self: return self def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[TracebackType]) -> None: diff --git a/chess/variant.py b/chess/variant.py index 119a0402c..d28a6e964 100644 --- a/chess/variant.py +++ b/chess/variant.py @@ -2,9 +2,13 @@ import chess import itertools +import typing from typing import Dict, Generic, Hashable, Iterable, Iterator, List, Optional, Type, TypeVar, Union +if typing.TYPE_CHECKING: + from typing_extensions import Self + class SuicideBoard(chess.Board): @@ -795,7 +799,7 @@ def _transposition_key(self) -> Hashable: return (super()._transposition_key(), self.remaining_checks[chess.WHITE], self.remaining_checks[chess.BLACK]) - def copy(self: ThreeCheckBoardT, stack: Union[bool, int] = True) -> ThreeCheckBoardT: + def copy(self, stack: Union[bool, int] = True) -> Self: board = super().copy(stack=stack) board.remaining_checks = self.remaining_checks.copy() if stack: @@ -803,7 +807,7 @@ def copy(self: ThreeCheckBoardT, stack: Union[bool, int] = True) -> ThreeCheckBo board._three_check_stack = self._three_check_stack[-stack:] return board - def root(self: ThreeCheckBoardT) -> ThreeCheckBoardT: + def root(self) -> Self: if self._three_check_stack: board = super().root() self._three_check_stack[0].restore(board) @@ -811,7 +815,7 @@ def root(self: ThreeCheckBoardT) -> ThreeCheckBoardT: else: return self.copy(stack=False) - def mirror(self: ThreeCheckBoardT) -> ThreeCheckBoardT: + def mirror(self) -> Self: board = super().mirror() board.remaining_checks[chess.WHITE] = self.remaining_checks[chess.BLACK] board.remaining_checks[chess.BLACK] = self.remaining_checks[chess.WHITE] @@ -865,7 +869,7 @@ def __len__(self) -> int: def __repr__(self) -> str: return f"CrazyhousePocket('{self}')" - def copy(self: CrazyhousePocketT) -> CrazyhousePocketT: + def copy(self) -> Self: """Returns a copy of this pocket.""" pocket = type(self)() pocket._pieces = self._pieces[:] @@ -1047,7 +1051,7 @@ def epd(self, shredder: bool = False, en_passant: chess.EnPassantSpec = "legal", board_part, info_part = epd.split(" ", 1) return f"{board_part}[{str(self.pockets[chess.WHITE]).upper()}{self.pockets[chess.BLACK]}] {info_part}" - def copy(self: CrazyhouseBoardT, stack: Union[bool, int] = True) -> CrazyhouseBoardT: + def copy(self, stack: Union[bool, int] = True) -> Self: board = super().copy(stack=stack) board.pockets[chess.WHITE] = self.pockets[chess.WHITE].copy() board.pockets[chess.BLACK] = self.pockets[chess.BLACK].copy() @@ -1056,7 +1060,7 @@ def copy(self: CrazyhouseBoardT, stack: Union[bool, int] = True) -> CrazyhouseBo board._crazyhouse_stack = self._crazyhouse_stack[-stack:] return board - def root(self: CrazyhouseBoardT) -> CrazyhouseBoardT: + def root(self) -> Self: if self._crazyhouse_stack: board = super().root() self._crazyhouse_stack[0].restore(board) @@ -1064,7 +1068,7 @@ def root(self: CrazyhouseBoardT) -> CrazyhouseBoardT: else: return self.copy(stack=False) - def mirror(self: CrazyhouseBoardT) -> CrazyhouseBoardT: + def mirror(self) -> Self: board = super().mirror() board.pockets[chess.WHITE] = self.pockets[chess.BLACK].copy() board.pockets[chess.BLACK] = self.pockets[chess.WHITE].copy() From f286d687e496123fb46d26ce3fd06bc0db505dc4 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 17:40:10 +0200 Subject: [PATCH 194/250] Towards pyright compatibility --- chess/__init__.py | 4 ++-- chess/engine.py | 7 +++++-- chess/variant.py | 8 ++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 3553eee65..55bd4cad2 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -1544,7 +1544,7 @@ def from_chess960_pos(cls: Type[BaseBoardT], scharnagl: int) -> BaseBoardT: class _BoardState: - def __init__(self, board: BoardT) -> None: + def __init__(self, board: Board) -> None: self.pawns = board.pawns self.knights = board.knights self.bishops = board.bishops @@ -1564,7 +1564,7 @@ def __init__(self, board: BoardT) -> None: self.halfmove_clock = board.halfmove_clock self.fullmove_number = board.fullmove_number - def restore(self, board: BoardT) -> None: + def restore(self, board: Board) -> None: board.pawns = self.pawns board.knights = self.knights board.bishops = self.bishops diff --git a/chess/engine.py b/chess/engine.py index 59b843b8b..9a6a21f48 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -406,8 +406,10 @@ class Score(abc.ABC): """ @typing.overload + @abc.abstractmethod def score(self, *, mate_score: int) -> int: ... @typing.overload + @abc.abstractmethod def score(self, *, mate_score: Optional[int] = None) -> Optional[int]: ... @abc.abstractmethod def score(self, *, mate_score: Optional[int] = None) -> Optional[int]: @@ -2120,12 +2122,13 @@ def _new(self, board: chess.Board, game: object, options: ConfigMapping, opponen if self.config.get("computer"): self.send_line("computer") - self.send_line("force") + self.send_line("force") - if new_game: fen = root.fen(shredder=board.chess960, en_passant="fen") if variant != "normal" or fen != chess.STARTING_FEN or board.chess960: self.send_line(f"setboard {fen}") + else: + self.send_line("force") # Undo moves until common position. common_stack_len = 0 diff --git a/chess/variant.py b/chess/variant.py index d28a6e964..6e9161dc8 100644 --- a/chess/variant.py +++ b/chess/variant.py @@ -133,7 +133,7 @@ def _transposition_key(self) -> Hashable: else: return super()._transposition_key() - def board_fen(self, promoted: Optional[bool] = None) -> str: + def board_fen(self, *, promoted: Optional[bool] = None) -> str: if promoted is None: promoted = self.has_chess960_castling_rights() return super().board_fen(promoted=promoted) @@ -799,7 +799,7 @@ def _transposition_key(self) -> Hashable: return (super()._transposition_key(), self.remaining_checks[chess.WHITE], self.remaining_checks[chess.BLACK]) - def copy(self, stack: Union[bool, int] = True) -> Self: + def copy(self, *, stack: Union[bool, int] = True) -> Self: board = super().copy(stack=stack) board.remaining_checks = self.remaining_checks.copy() if stack: @@ -1041,7 +1041,7 @@ def set_fen(self, fen: str) -> None: self.pockets[chess.WHITE] = white_pocket self.pockets[chess.BLACK] = black_pocket - def board_fen(self, promoted: Optional[bool] = None) -> str: + def board_fen(self, *, promoted: Optional[bool] = None) -> str: if promoted is None: promoted = True return super().board_fen(promoted=promoted) @@ -1051,7 +1051,7 @@ def epd(self, shredder: bool = False, en_passant: chess.EnPassantSpec = "legal", board_part, info_part = epd.split(" ", 1) return f"{board_part}[{str(self.pockets[chess.WHITE]).upper()}{self.pockets[chess.BLACK]}] {info_part}" - def copy(self, stack: Union[bool, int] = True) -> Self: + def copy(self, *, stack: Union[bool, int] = True) -> Self: board = super().copy(stack=stack) board.pockets[chess.WHITE] = self.pockets[chess.WHITE].copy() board.pockets[chess.BLACK] = self.pockets[chess.BLACK].copy() From 33eea7ca062ed7396590ac3408ec05121bba9483 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 18:01:47 +0200 Subject: [PATCH 195/250] Add changelog entries --- CHANGELOG.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a4534badb..754b5d418 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,13 @@ Changes: some 8 piece positions with decisive captures can be probed successfully. * The string wrapper returned by ``chess.svg`` functions now also implements ``_repr_html_``. +* Significant changes to ``chess.engine`` internals: + ``chess.engine.BaseCommand`` methods other than the constructor no longer + receive ``engine: Protocol``. +* Significant changes to board state internals: Subclasses of ``chess.Board`` + can no longer hook into board state recording/restoration and need to + override relevant methods instead (``clear_stack``, ``copy``, ``root``, + ``push``, ``pop``). New features: From caefd4dc6c25369750f6cc461885adfbbd52f09c Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 21:11:38 +0200 Subject: [PATCH 196/250] chess.engine._next_token() cosmetics --- chess/engine.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 9a6a21f48..c6698bc76 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -2650,7 +2650,8 @@ def _parse_xboard_post(line: str, root_board: chess.Board, selector: Info = INFO def _next_token(line: str) -> tuple[str, str]: - """Get the next token in a whitespace-delimited line of text. + """ + Get the next token in a whitespace-delimited line of text. The result is returned as a 2-part tuple of strings. @@ -2660,10 +2661,10 @@ def _next_token(line: str) -> tuple[str, str]: If the input line is not empty and not completely whitespace, then the first element of the returned tuple is a single word with leading and trailing whitespace removed. The second element is the - unchanged rest of the line.""" - + unchanged rest of the line. + """ parts = line.split(maxsplit=1) - return (parts[0] if parts else "", parts[1] if len(parts) == 2 else "") + return parts[0] if parts else "", parts[1] if len(parts) == 2 else "" class BestMove: From 71e7c31fba31554a2b174ff7fb88a77b61674543 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 22:21:28 +0200 Subject: [PATCH 197/250] Show actual state in engine command state assertions (#1049, #1071) --- chess/engine.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c6698bc76..302aa2bbd 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -989,7 +989,7 @@ async def communicate(self, command_factory: Callable[[Self], BaseCommand[T]]) - if self.returncode.done(): raise EngineTerminatedError(f"engine process dead (exit code: {self.returncode.result()})") - assert command.state == CommandState.NEW + assert command.state == CommandState.NEW, command.state if self.next_command is not None: self.next_command.result.cancel() @@ -1253,7 +1253,7 @@ def _handle_exception(self, exc: Exception) -> None: self.finished.set_result(None) def set_finished(self) -> None: - assert self.state in [CommandState.ACTIVE, CommandState.CANCELLING] + assert self.state in [CommandState.ACTIVE, CommandState.CANCELLING], self.state if not self.result.done(): self.result.set_exception(EngineError(f"engine command finished before returning result: {self!r}")) self.finished.set_result(None) @@ -1261,12 +1261,12 @@ def set_finished(self) -> None: def _cancel(self) -> None: if self.state != CommandState.CANCELLING and self.state != CommandState.DONE: - assert self.state == CommandState.ACTIVE + assert self.state == CommandState.ACTIVE, self.state self.state = CommandState.CANCELLING self.cancel() def _start(self) -> None: - assert self.state == CommandState.NEW + assert self.state == CommandState.NEW, self.state self.state = CommandState.ACTIVE try: self.check_initialized() @@ -1275,7 +1275,7 @@ def _start(self) -> None: self._handle_exception(err) def _line_received(self, line: str) -> None: - assert self.state in [CommandState.ACTIVE, CommandState.CANCELLING] + assert self.state in [CommandState.ACTIVE, CommandState.CANCELLING], self.state try: self.line_received(line) except EngineError as err: From 7299216641f5bd0434c06111608892617aa39147 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 31 Jul 2024 22:37:53 +0200 Subject: [PATCH 198/250] Immediately dispatch line/termination/finish (fixes #1049, fixes #1071) Avoids races between queued up lines and command finish callbacks. --- CHANGELOG.rst | 2 ++ chess/engine.py | 40 +++++++++++++++++++++++++++------------- test.py | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 754b5d418..9a0a16e6c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,8 @@ New features: Bugfixes: +* Fix unsolicited engine output may cause assertion errors with regard to + command states. * Fix handling of whitespace in UCI engine communication. * For ``chess.Board.epd()`` and ``chess.Board.set_epd()``, require that EPD opcodes start with a letter. diff --git a/chess/engine.py b/chess/engine.py index 302aa2bbd..ccd6894d2 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -883,7 +883,7 @@ def write(self, data: bytes) -> None: expectation, responses = self.expectations.popleft() assert expectation == line, f"expected {expectation}, got: {line}" if responses: - self.protocol.pipe_data_received(1, "\n".join(responses + [""]).encode("utf-8")) + self.protocol.loop.call_soon(self.protocol.pipe_data_received, 1, "\n".join(responses + [""]).encode("utf-8")) def get_pid(self) -> int: return id(self) @@ -934,12 +934,12 @@ def connection_lost(self, exc: Optional[Exception]) -> None: LOGGER.debug("%s: Connection lost (exit code: %d, error: %s)", self, code, exc) # Terminate commands. - if self.command is not None: - self.command._engine_terminated(code) - self.command = None - if self.next_command is not None: - self.next_command._engine_terminated(code) - self.next_command = None + command, self.command = self.command, None + next_command, self.next_command = self.next_command, None + if command: + command._engine_terminated(code) + if next_command: + next_command._engine_terminated(code) self.returncode.set_result(code) @@ -965,9 +965,9 @@ def pipe_data_received(self, fd: int, data: Union[bytes, str]) -> None: LOGGER.warning("%s: >> %r (%s)", self, bytes(line_bytes), err) else: if fd == 1: - self.loop.call_soon(self._line_received, line) + self._line_received(line) else: - self.loop.call_soon(self.error_line_received, line) + self.error_line_received(line) def error_line_received(self, line: str) -> None: LOGGER.warning("%s: stderr >> %s", self, line) @@ -998,7 +998,7 @@ async def communicate(self, command_factory: Callable[[Self], BaseCommand[T]]) - self.next_command = command - def previous_command_finished(_: Optional[asyncio.Future[None]]) -> None: + def previous_command_finished() -> None: self.command, self.next_command = self.next_command, None if self.command is not None: cmd = self.command @@ -1008,11 +1008,11 @@ def cancel_if_cancelled(result: asyncio.Future[T]) -> None: cmd._cancel() cmd.result.add_done_callback(cancel_if_cancelled) - cmd.finished.add_done_callback(previous_command_finished) cmd._start() + cmd.add_finished_callback(previous_command_finished) if self.command is None: - previous_command_finished(None) + previous_command_finished() elif not self.command.result.done(): self.command.result.cancel() elif not self.command.result.cancelled(): @@ -1228,6 +1228,17 @@ def __init__(self, engine: Protocol) -> None: self.result: asyncio.Future[T] = asyncio.Future() self.finished: asyncio.Future[None] = asyncio.Future() + self._finished_callbacks: List[Callable[[], None]] = [] + + def add_finished_callback(self, callback: Callable[[], None]) -> None: + self._finished_callbacks.append(callback) + self._dispatch_finished() + + def _dispatch_finished(self) -> None: + if self.finished.done(): + while self._finished_callbacks: + self._finished_callbacks.pop()() + def _engine_terminated(self, code: int) -> None: hint = ", binary not compatible with cpu?" if code in [-4, 0xc000001d] else "" exc = EngineTerminatedError(f"engine process died unexpectedly (exit code: {code}{hint})") @@ -1235,6 +1246,7 @@ def _engine_terminated(self, code: int) -> None: self.engine_terminated(exc) elif self.state == CommandState.CANCELLING: self.finished.set_result(None) + self._dispatch_finished() elif self.state == CommandState.NEW: self._handle_exception(exc) @@ -1251,13 +1263,15 @@ def _handle_exception(self, exc: Exception) -> None: if not self.finished.done(): self.finished.set_result(None) + self._dispatch_finished() def set_finished(self) -> None: assert self.state in [CommandState.ACTIVE, CommandState.CANCELLING], self.state if not self.result.done(): self.result.set_exception(EngineError(f"engine command finished before returning result: {self!r}")) - self.finished.set_result(None) self.state = CommandState.DONE + self.finished.set_result(None) + self._dispatch_finished() def _cancel(self) -> None: if self.state != CommandState.CANCELLING and self.state != CommandState.DONE: diff --git a/test.py b/test.py index 00d766a03..438628b98 100755 --- a/test.py +++ b/test.py @@ -3527,6 +3527,24 @@ async def main(): asyncio.run(main()) + def test_uci_output_after_command(self): + async def main(): + protocol = chess.engine.UciProtocol() + mock = chess.engine.MockTransport(protocol) + + mock.expect("uci", [ + "Arasan v24.0.0-10-g367aa9f Copyright 1994-2023 by Jon Dart.", + "All rights reserved.", + "id name Arasan v24.0.0-10-g367aa9f", + "uciok", + "info string out of do_all_pending, list size=0" + ]) + await protocol.initialize() + + mock.assert_done() + + asyncio.run(main()) + def test_hiarcs_bestmove(self): async def main(): protocol = chess.engine.UciProtocol() From 7fa1f1825bc504ad50724e848b0e982b526c9f87 Mon Sep 17 00:00:00 2001 From: Lukas Malte Monnerjahn Date: Thu, 5 Sep 2024 11:31:03 +0200 Subject: [PATCH 199/250] SVG: Align pieces, check mark, selected squares and arrows correctly when rendering a border #1103 --- chess/svg.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index 2948b0b80..c665b171b 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -283,6 +283,7 @@ def board(board: Optional[chess.BaseBoard] = None, *, inner_border = 1 if borders and coordinates else 0 outer_border = 1 if borders else 0 margin = 15 if coordinates else 0 + board_offset = inner_border + margin + outer_border full_size = 2 * outer_border + 2 * margin + 2 * inner_border + 8 * SQUARE_SIZE svg = _svg(full_size, size) @@ -351,12 +352,12 @@ def board(board: Optional[chess.BaseBoard] = None, *, if coordinates: coord_color, coord_opacity = _select_color(colors, "coord") for file_index, file_name in enumerate(chess.FILE_NAMES): - x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + inner_border + margin + outer_border + x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + board_offset # Keep some padding here to separate the ascender from the border svg.append(_coord(file_name, x, 1, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity)) svg.append(_coord(file_name, x, full_size - outer_border - margin, SQUARE_SIZE, margin, True, margin, color=coord_color, opacity=coord_opacity)) for rank_index, rank_name in enumerate(chess.RANK_NAMES): - y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + inner_border + margin + outer_border + y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + board_offset svg.append(_coord(rank_name, 0, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity)) svg.append(_coord(rank_name, full_size - outer_border - margin, y, margin, SQUARE_SIZE, False, margin, color=coord_color, opacity=coord_opacity)) @@ -365,8 +366,8 @@ def board(board: Optional[chess.BaseBoard] = None, *, file_index = chess.square_file(square) rank_index = chess.square_rank(square) - x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + inner_border + margin + outer_border - y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + inner_border + margin + outer_border + x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + board_offset + y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + board_offset cls = ["square", "light" if chess.BB_LIGHT_SQUARES & bb else "dark"] if lastmove and square in [lastmove.from_square, lastmove.to_square]: @@ -406,8 +407,8 @@ def board(board: Optional[chess.BaseBoard] = None, *, file_index = chess.square_file(check) rank_index = chess.square_rank(check) - x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin - y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin + x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + board_offset + y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + board_offset ET.SubElement(svg, "rect", _attrs({ "x": x, @@ -423,8 +424,8 @@ def board(board: Optional[chess.BaseBoard] = None, *, file_index = chess.square_file(square) rank_index = chess.square_rank(square) - x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + margin - y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + margin + x = (file_index if orientation else 7 - file_index) * SQUARE_SIZE + board_offset + y = (7 - rank_index if orientation else rank_index) * SQUARE_SIZE + board_offset if board is not None: piece = board.piece_at(square) @@ -463,10 +464,10 @@ def board(board: Optional[chess.BaseBoard] = None, *, head_file = chess.square_file(head) head_rank = chess.square_rank(head) - xtail = outer_border + margin + inner_border + (tail_file + 0.5 if orientation else 7.5 - tail_file) * SQUARE_SIZE - ytail = outer_border + margin + inner_border + (7.5 - tail_rank if orientation else tail_rank + 0.5) * SQUARE_SIZE - xhead = outer_border + margin + inner_border + (head_file + 0.5 if orientation else 7.5 - head_file) * SQUARE_SIZE - yhead = outer_border + margin + inner_border + (7.5 - head_rank if orientation else head_rank + 0.5) * SQUARE_SIZE + xtail = board_offset + (tail_file + 0.5 if orientation else 7.5 - tail_file) * SQUARE_SIZE + ytail = board_offset + (7.5 - tail_rank if orientation else tail_rank + 0.5) * SQUARE_SIZE + xhead = board_offset + (head_file + 0.5 if orientation else 7.5 - head_file) * SQUARE_SIZE + yhead = board_offset + (7.5 - head_rank if orientation else head_rank + 0.5) * SQUARE_SIZE if (head_file, head_rank) == (tail_file, tail_rank): ET.SubElement(svg, "circle", _attrs({ From 0e7fabc8ae0127a994aaece31e3c69a510cef527 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 27 Sep 2024 17:37:16 +0200 Subject: [PATCH 200/250] Test reading PGN with UTF-8 BOM --- data/pgn/utf8-bom.pgn | 26 ++++++++++++++++++++++++++ test.py | 12 ++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 data/pgn/utf8-bom.pgn diff --git a/data/pgn/utf8-bom.pgn b/data/pgn/utf8-bom.pgn new file mode 100644 index 000000000..665e7775a --- /dev/null +++ b/data/pgn/utf8-bom.pgn @@ -0,0 +1,26 @@ +[Event "A"] +[Site "?"] +[Date "2024.04.25"] +[Round "?"] +[White "White vs 1...c5"] +[Black "?"] +[Result "*"] +[ECO "A00"] +[PlyCount "0"] +[SourceVersionDate "2024.04.25"] + + * + +[Event "B"] +[Site "?"] +[Date "2024.04.25"] +[Round "?"] +[White "White vs 1...c5"] +[Black "?"] +[Result "*"] +[ECO "A00"] +[PlyCount "0"] +[SourceVersionDate "2024.04.25"] + + * + diff --git a/test.py b/test.py index 438628b98..6102eabdb 100755 --- a/test.py +++ b/test.py @@ -2947,6 +2947,18 @@ def end_variation(self): game = chess.pgn.read_game(io.StringIO(pgn)).accept(BlackVariationsOnly()) self.assertEqual(game.accept(chess.pgn.StringExporter(headers=False)), expected_pgn) + def test_utf8_bom(self): + not_utf8_sig = "utf-8" + with open("data/pgn/utf8-bom.pgn", encoding=not_utf8_sig) as pgn: + game = chess.pgn.read_game(pgn) + self.assertEqual(game.headers["Event"], "A") + + game = chess.pgn.read_game(pgn) + self.assertEqual(game.headers["Event"], "B") + + game = chess.pgn.read_game(pgn) + self.assertEqual(game, None) + @unittest.skipIf(sys.platform == "win32" and (3, 8, 0) <= sys.version_info < (3, 8, 1), "https://bugs.python.org/issue34679") class EngineTestCase(unittest.TestCase): From c0d3c9171d22d0168a6cf7a584cdcf50909832e6 Mon Sep 17 00:00:00 2001 From: evidencebp Date: Thu, 3 Oct 2024 14:33:20 +0300 Subject: [PATCH 201/250] chess\__init__.py superfluous-parens There are two such alerts in this file. One has two terms and the parentheses do not contribute to readability. The other term is longer and the parenthesis help to readability and therefore are kept. --- chess/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/__init__.py b/chess/__init__.py index 55bd4cad2..9d6e869fe 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -3402,7 +3402,7 @@ def clean_castling_rights(self) -> Bitboard: if white_h_side and msb(white_h_side) < msb(white_king_mask): white_h_side = 0 - black_a_side = (black_castling & -black_castling) + black_a_side = black_castling & -black_castling black_h_side = BB_SQUARES[msb(black_castling)] if black_castling else BB_EMPTY if black_a_side and msb(black_a_side) > msb(black_king_mask): From 30d991046908ce7c5a7929987c1c2081f68641b4 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 4 Oct 2024 18:33:54 +0200 Subject: [PATCH 202/250] Prepare 1.11.0 --- CHANGELOG.rst | 4 ++-- chess/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9a0a16e6c..296079f24 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,8 +1,8 @@ Changelog for python-chess ========================== -Upcoming in the next release ----------------------------- +New in v1.11.0 (4th Oct 2024) +----------------------------- Changes: diff --git a/chess/__init__.py b/chess/__init__.py index 9d6e869fe..147f24be7 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -11,7 +11,7 @@ __email__ = "niklas.fiekas@backscattering.de" -__version__ = "1.10.0" +__version__ = "1.11.0" import collections import copy From 46c28883f7846f87f419c5c83e7c61e3cdea5d36 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 4 Oct 2024 18:44:53 +0200 Subject: [PATCH 203/250] Revert "Removed unnecessary indentation blocks and updated conditional statements." This reverts commit 4a6dd9a89b7810312ab4ea1cf255d1a501ae09ca. --- release.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/release.py b/release.py index f2f7d81fa..d27ddf04e 100755 --- a/release.py +++ b/release.py @@ -10,7 +10,7 @@ def system(command): print(command) exit_code = os.system(command) - if exit_code: + if exit_code != 0: sys.exit(exit_code) @@ -21,7 +21,7 @@ def check_git(): system("git fetch origin") behind = int(subprocess.check_output(["git", "rev-list", "--count", "master..origin/master"])) - if behind: + if behind > 0: print(f"master is {behind} commit(s) behind origin/master") sys.exit(1) @@ -65,14 +65,15 @@ def tag_and_push(): release_txt.write(headline + os.linesep) for line in changelog_file: - if line.startswith("-------") and not first_section: - first_section = True + if not first_section: + if line.startswith("-------"): + first_section = True else: if line.startswith("-------"): break - - if not prev_line.startswith("------"): - release_txt.write(prev_line) + else: + if not prev_line.startswith("------"): + release_txt.write(prev_line) prev_line = line From 08697b298d87e4fa01842bd82af96d71cb972c90 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 4 Oct 2024 18:57:48 +0200 Subject: [PATCH 204/250] Fix twine usage, stop uploading wheels --- release.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release.py b/release.py index d27ddf04e..4057ab785 100755 --- a/release.py +++ b/release.py @@ -97,9 +97,9 @@ def tag_and_push(): def pypi(): print("--- PYPI ---------------------------------------------------------") system("rm -rf build") - system("python3 setup.py sdist bdist_wheel") + system("python3 setup.py sdist") system("twine check dist/*") - system("twine upload --skip-existing") + system("twine upload --skip-existing dist/*") def github_release(tagname): From 611221de07fa7679b5d00b712cf8472ce66e6b38 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 7 Oct 2024 20:08:23 -0700 Subject: [PATCH 205/250] Fix error when parsing UCI options The regex that splits a UCI option into parts did not include word boundries, so words like "mini" would be split into "min" and "i", leading to parse errors. This commit puts word boundries into the regex to fix this. Fixes #1112 --- chess/engine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index ccd6894d2..270e31e71 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1367,7 +1367,8 @@ def _option(self, arg: str) -> None: var = [] parameters = list(option_parts.keys()) + ['var'] - option_regex = fr"\s*({'|'.join(parameters)})\s*" + inner_regex = '|'.join([fr"\b{parameter}\b" for parameter in parameters]) + option_regex = fr"\s*({inner_regex})\s*" for token in re.split(option_regex, arg.strip()): if token == "var" or (token in option_parts and not option_parts[token]): current_parameter = token From 54b18de726e0f1d06f89f35104c66ddeb527fac7 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 7 Oct 2024 22:38:29 -0700 Subject: [PATCH 206/250] Add test for options fix Test uses fairy-stockfish since that engine revealed the original bug. --- test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test.py b/test.py index 2a1df1c85..9903b208d 100755 --- a/test.py +++ b/test.py @@ -3142,6 +3142,11 @@ def test_sf_quit(self): with self.assertRaises(chess.engine.EngineTerminatedError), engine: engine.ping() + @catchAndSkip(FileNotFoundError, "need fairy-stockfish") + def test_fairy_sf_initialize(self): + with chess.engine.SimpleEngine.popen_uci("fairy-stockfish", setpgrp=True, debug=True): + pass + @catchAndSkip(FileNotFoundError, "need crafty") def test_crafty_play_to_mate(self): logging.disable(logging.WARNING) From ebb687c5dab328d91a055b1f63dabf6c28739ed2 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 7 Oct 2024 22:58:59 -0700 Subject: [PATCH 207/250] Make test functional by installing fairy-stockfish --- .github/workflows/setup-ubuntu-latest.sh | 3 +++ .github/workflows/setup-windows-latest.sh | 6 +++++- tox.ini | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/setup-ubuntu-latest.sh b/.github/workflows/setup-ubuntu-latest.sh index fae35b61a..10b8d1115 100755 --- a/.github/workflows/setup-ubuntu-latest.sh +++ b/.github/workflows/setup-ubuntu-latest.sh @@ -6,6 +6,9 @@ sudo apt-get install -y stockfish # Crafty sudo apt-get install -y crafty +# Fairy-stockfish +sudo apt-get install -y fairy-stockfish + # Gaviota libgtb git clone https://github.com/michiguel/Gaviota-Tablebases.git --depth 1 cd Gaviota-Tablebases diff --git a/.github/workflows/setup-windows-latest.sh b/.github/workflows/setup-windows-latest.sh index 815eb0db2..48037cbef 100755 --- a/.github/workflows/setup-windows-latest.sh +++ b/.github/workflows/setup-windows-latest.sh @@ -1,6 +1,6 @@ #!/bin/sh -e -echo Download ... +echo Download stockfish ... choco install wget wget https://github.com/official-stockfish/Stockfish/releases/download/sf_16/stockfish-windows-x86-64-avx2.zip @@ -10,3 +10,7 @@ echo Unzip .. echo Setup path ... mv stockfish-windows-x86-64-avx2.exe stockfish.exe pwd >> $GITHUB_PATH + +echo Download fairy-stockfish ... +wget https://github.com/fairy-stockfish/Fairy-Stockfish/releases/latest/download/fairy-stockfish-largeboard_x86-64.exe +mv fairy-stockfish-largeboard_x86-64.exe fairy-stockfish.exe diff --git a/tox.ini b/tox.ini index f629723cd..8d8033676 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ passenv = LD_LIBRARY_PATH whitelist_externals = stockfish crafty + fairy-stockfish commands = python test.py --verbose python -m doctest README.rst --verbose From c0ac01b784bf1c63abb325424ea9e7bb2cb3f44e Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 7 Oct 2024 23:13:27 -0700 Subject: [PATCH 208/250] Add test using MockTransport --- test.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test.py b/test.py index 9903b208d..e490daa90 100755 --- a/test.py +++ b/test.py @@ -3147,6 +3147,21 @@ def test_fairy_sf_initialize(self): with chess.engine.SimpleEngine.popen_uci("fairy-stockfish", setpgrp=True, debug=True): pass + def test_uci_option_parse(self): + async def main(): + protocol = chess.engine.UciProtocol() + mock = chess.engine.MockTransport(protocol) + + mock.expect("uci", ["option name UCI_Variant type combo default chess var bughouse var chess var mini var minishogi var threekings", "uciok"]) + await protocol.initialize() + mock.assert_done() + + mock.expect("isready", ["readyok"]) + await protocol.ping() + mock.assert_done() + + asyncio.run(main()) + @catchAndSkip(FileNotFoundError, "need crafty") def test_crafty_play_to_mate(self): logging.disable(logging.WARNING) From fa4f0148f683c8e59ffa762f93045f9edfc69994 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 8 Oct 2024 22:07:21 +0200 Subject: [PATCH 209/250] Merge pull request #1113 from MarkZH/options-fix Fix error when parsing UCI options --- .github/workflows/setup-ubuntu-latest.sh | 3 +++ .github/workflows/setup-windows-latest.sh | 6 +++++- chess/engine.py | 3 ++- test.py | 20 ++++++++++++++++++++ tox.ini | 1 + 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/setup-ubuntu-latest.sh b/.github/workflows/setup-ubuntu-latest.sh index fae35b61a..10b8d1115 100755 --- a/.github/workflows/setup-ubuntu-latest.sh +++ b/.github/workflows/setup-ubuntu-latest.sh @@ -6,6 +6,9 @@ sudo apt-get install -y stockfish # Crafty sudo apt-get install -y crafty +# Fairy-stockfish +sudo apt-get install -y fairy-stockfish + # Gaviota libgtb git clone https://github.com/michiguel/Gaviota-Tablebases.git --depth 1 cd Gaviota-Tablebases diff --git a/.github/workflows/setup-windows-latest.sh b/.github/workflows/setup-windows-latest.sh index 815eb0db2..48037cbef 100755 --- a/.github/workflows/setup-windows-latest.sh +++ b/.github/workflows/setup-windows-latest.sh @@ -1,6 +1,6 @@ #!/bin/sh -e -echo Download ... +echo Download stockfish ... choco install wget wget https://github.com/official-stockfish/Stockfish/releases/download/sf_16/stockfish-windows-x86-64-avx2.zip @@ -10,3 +10,7 @@ echo Unzip .. echo Setup path ... mv stockfish-windows-x86-64-avx2.exe stockfish.exe pwd >> $GITHUB_PATH + +echo Download fairy-stockfish ... +wget https://github.com/fairy-stockfish/Fairy-Stockfish/releases/latest/download/fairy-stockfish-largeboard_x86-64.exe +mv fairy-stockfish-largeboard_x86-64.exe fairy-stockfish.exe diff --git a/chess/engine.py b/chess/engine.py index ccd6894d2..270e31e71 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1367,7 +1367,8 @@ def _option(self, arg: str) -> None: var = [] parameters = list(option_parts.keys()) + ['var'] - option_regex = fr"\s*({'|'.join(parameters)})\s*" + inner_regex = '|'.join([fr"\b{parameter}\b" for parameter in parameters]) + option_regex = fr"\s*({inner_regex})\s*" for token in re.split(option_regex, arg.strip()): if token == "var" or (token in option_parts and not option_parts[token]): current_parameter = token diff --git a/test.py b/test.py index 6102eabdb..9e2f9d166 100755 --- a/test.py +++ b/test.py @@ -3134,6 +3134,26 @@ def test_sf_quit(self): with self.assertRaises(chess.engine.EngineTerminatedError), engine: engine.ping() + @catchAndSkip(FileNotFoundError, "need fairy-stockfish") + def test_fairy_sf_initialize(self): + with chess.engine.SimpleEngine.popen_uci("fairy-stockfish", setpgrp=True, debug=True): + pass + + def test_uci_option_parse(self): + async def main(): + protocol = chess.engine.UciProtocol() + mock = chess.engine.MockTransport(protocol) + + mock.expect("uci", ["option name UCI_Variant type combo default chess var bughouse var chess var mini var minishogi var threekings", "uciok"]) + await protocol.initialize() + mock.assert_done() + + mock.expect("isready", ["readyok"]) + await protocol.ping() + mock.assert_done() + + asyncio.run(main()) + @catchAndSkip(FileNotFoundError, "need crafty") def test_crafty_play_to_mate(self): logging.disable(logging.WARNING) diff --git a/tox.ini b/tox.ini index f629723cd..8d8033676 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ passenv = LD_LIBRARY_PATH whitelist_externals = stockfish crafty + fairy-stockfish commands = python test.py --verbose python -m doctest README.rst --verbose From ffc6da935642654ee13eda3bb649a8748531b960 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 9 Oct 2024 20:24:42 +0200 Subject: [PATCH 210/250] Prepare 1.11.1 --- CHANGELOG.rst | 8 ++++++++ chess/__init__.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 296079f24..05b899a20 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ Changelog for python-chess ========================== +New in v1.11.1 (9th Oct 2024) +----------------------------- + +Bugfixes: + +* ``chess.engine``: Fix parsing of UCI options containing containing ``name``, + ``type``, ``default``, ``min``, or ``max``, e.g., ``mini``. + New in v1.11.0 (4th Oct 2024) ----------------------------- diff --git a/chess/__init__.py b/chess/__init__.py index 147f24be7..a6a66500e 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -11,7 +11,7 @@ __email__ = "niklas.fiekas@backscattering.de" -__version__ = "1.11.0" +__version__ = "1.11.1" import collections import copy From 7f123cb5dd858978de4a32b7d2c8f8ea71a3552c Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 9 Oct 2024 20:35:10 +0200 Subject: [PATCH 211/250] Remove chess.svg.board(..., flipped), use orientation (#659) --- chess/svg.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/chess/svg.py b/chess/svg.py index c665b171b..7e8facf99 100644 --- a/chess/svg.py +++ b/chess/svg.py @@ -227,7 +227,6 @@ def board(board: Optional[chess.BaseBoard] = None, *, size: Optional[int] = None, coordinates: bool = True, colors: Dict[str, str] = {}, - flipped: bool = False, borders: bool = False, style: Optional[str] = None) -> str: """ @@ -255,7 +254,6 @@ def board(board: Optional[chess.BaseBoard] = None, *, ``outer border``, ``arrow green``, ``arrow blue``, ``arrow red``, and ``arrow yellow``. Values should look like ``#ffce9e`` (opaque), or ``#15781B80`` (transparent). - :param flipped: Pass ``True`` to flip the board. :param borders: Pass ``True`` to enable a border around the board and, (if *coordinates* is enabled) the coordinate margin. :param style: A CSS stylesheet to include in the SVG image. @@ -275,11 +273,7 @@ def board(board: Optional[chess.BaseBoard] = None, *, .. image:: ../docs/Ne4.svg :alt: 8/8/8/8/4N3/8/8/8 - - .. deprecated:: 1.1 - Use *orientation* with a color instead of the *flipped* toggle. """ - orientation ^= flipped inner_border = 1 if borders and coordinates else 0 outer_border = 1 if borders else 0 margin = 15 if coordinates else 0 From f2b0452389c4272948b253ac6266eb89ac85c179 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 9 Oct 2024 20:37:08 +0200 Subject: [PATCH 212/250] Remove deprecated chess.pgn.BaseVisitor.parse_san() (#659) --- chess/pgn.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index bded9ae5d..eddb6bc52 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1104,22 +1104,6 @@ def begin_parse_san(self, board: chess.Board, san: str) -> Optional[SkipType]: """ pass - def parse_san(self, board: chess.Board, san: str) -> chess.Move: - """ - When the visitor is used by a parser, this is called to parse a move - in standard algebraic notation. - - You can override the default implementation to work around specific - quirks of your input format. - - .. deprecated:: 1.1 - This method is very limited, because it is only called on moves - that the parser recognizes in the first place. Instead of adding - workarounds here, please report common quirks so that - they can be handled for everyone. - """ - return board.parse_san(san) - def visit_move(self, board: chess.Board, move: chess.Move) -> None: """ Called for each move. @@ -1751,7 +1735,7 @@ def read_game(handle: TextIO, *, Visitor: Any = GameBuilder) -> Any: # Parse SAN tokens. if visitor.begin_parse_san(board_stack[-1], token) is not SKIP: try: - move = visitor.parse_san(board_stack[-1], token) + move = board_stack[-1].parse_san(token) except ValueError as error: visitor.handle_error(error) skip_variation_depth = 1 From b2657ebc4768e2815cb8ddeb8c9ed13109332e15 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 9 Oct 2024 20:41:43 +0200 Subject: [PATCH 213/250] Remove deprecated chess.engine.Wdl tuple behavior (#659) --- chess/engine.py | 45 +-------------------------------------------- test.py | 2 +- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index 270e31e71..64a3926b7 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -720,16 +720,11 @@ def __str__(self) -> str: MateGiven = MateGivenType() +@dataclasses.dataclass class PovWdl: """ Relative :class:`win/draw/loss statistics ` and the point of view. - - .. deprecated:: 1.2 - Behaves like a tuple - ``(wdl.relative.wins, wdl.relative.draws, wdl.relative.losses)`` - for backwards compatibility. But it is recommended to use the provided - fields and methods instead. """ relative: Wdl @@ -738,10 +733,6 @@ class PovWdl: turn: Color """The point of view (``chess.WHITE`` or ``chess.BLACK``).""" - def __init__(self, relative: Wdl, turn: Color) -> None: - self.relative = relative - self.turn = turn - def white(self) -> Wdl: """Gets the :class:`~chess.engine.Wdl` from White's point of view.""" return self.pov(chess.WHITE) @@ -763,30 +754,6 @@ def __bool__(self) -> bool: def __repr__(self) -> str: return "PovWdl({!r}, {})".format(self.relative, "WHITE" if self.turn else "BLACK") - # Unfortunately in python-chess v1.1.0, info["wdl"] was a simple tuple - # of the relative permille values, so we have to support __iter__, - # __len__, __getitem__, and equality comparisons with other tuples. - # Never mind the ordering, because that's not a sensible operation, anyway. - - def __iter__(self) -> Iterator[int]: - yield self.relative.wins - yield self.relative.draws - yield self.relative.losses - - def __len__(self) -> int: - return 3 - - def __getitem__(self, idx: int) -> int: - return (self.relative.wins, self.relative.draws, self.relative.losses)[idx] - - def __eq__(self, other: object) -> bool: - if isinstance(other, PovWdl): - return self.white() == other.white() - elif isinstance(other, tuple): - return (self.relative.wins, self.relative.draws, self.relative.losses) == other - else: - return NotImplemented - @dataclasses.dataclass class Wdl: @@ -830,16 +797,6 @@ def expectation(self) -> float: def __bool__(self) -> bool: return bool(self.total()) - def __iter__(self) -> Iterator[int]: - yield self.wins - yield self.draws - yield self.losses - - def __reversed__(self) -> Iterator[int]: - yield self.losses - yield self.draws - yield self.wins - def __pos__(self) -> Wdl: return self diff --git a/test.py b/test.py index e490daa90..68904a50e 100755 --- a/test.py +++ b/test.py @@ -3540,7 +3540,7 @@ def test_uci_info(self): # WDL (activated with UCI_ShowWDL). info = chess.engine._parse_uci_info("depth 1 seldepth 2 time 16 nodes 1 score cp 72 wdl 249 747 4 hashfull 0 nps 400 tbhits 0 multipv 1", board) - self.assertEqual(info["wdl"], (249, 747, 4)) + self.assertEqual(info["wdl"].white(), chess.engine.Wdl(249, 747, 4)) def test_uci_result(self): async def main(): From 6228bac55b8e680362f35e69c1c72a4d53d00cf4 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 12 Oct 2024 20:50:29 +0200 Subject: [PATCH 214/250] Update Sphinx --- docs/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 7516f64de..c04e3554a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ -Sphinx==7.3.6 +Sphinx==8.1.2 sphinxcontrib-jquery==4.1 -sphinx-rtd-theme==1.3.0 +sphinx-rtd-theme==3.0.1 From e2041699939d7ae08811fe7a1391e8910d5ec62a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 11:12:49 +0200 Subject: [PATCH 215/250] Towards passing pyright --- chess/__init__.py | 10 +++++++--- chess/engine.py | 2 +- chess/syzygy.py | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 147f24be7..4f5791f7c 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -1218,6 +1218,8 @@ def _set_chess960_pos(self, scharnagl: int) -> None: n, bb = divmod(n, 4) n, q = divmod(n, 6) + n1 = 0 + n2 = 0 for n1 in range(0, 4): n2 = n + (3 - n1) * (4 - n1) // 2 - 5 if n1 < n2 and 1 <= n2 <= 4: @@ -2394,7 +2396,7 @@ def push(self, move: Move) -> None: elif move.to_square == ep_square and abs(diff) in [7, 9] and not captured_piece_type: # Remove pawns captured en passant. down = -8 if self.turn == WHITE else 8 - capture_square = ep_square + down + capture_square = move.to_square + down captured_piece_type = self._remove_piece_at(capture_square) # Promotion. @@ -3166,6 +3168,8 @@ def parse_san(self, san: str) -> Move: # Filter by original square. from_mask = BB_ALL + from_file = None + from_rank = None if match.group(2): from_file = FILE_NAMES.index(match.group(2)) from_mask &= BB_FILES[from_file] @@ -3177,7 +3181,7 @@ def parse_san(self, san: str) -> Move: if match.group(1): piece_type = PIECE_SYMBOLS.index(match.group(1).lower()) from_mask &= self.pieces_mask(piece_type, self.turn) - elif match.group(2) and match.group(3): + elif from_file is not None and from_rank is not None: # Allow fully specified moves, even if they are not pawn moves, # including castling moves. move = self.find_move(square(from_file, from_rank), to_square, promotion) @@ -3189,7 +3193,7 @@ def parse_san(self, san: str) -> Move: from_mask &= self.pawns # Do not allow pawn captures if file is not specified. - if not match.group(2): + if from_file is None: from_mask &= BB_FILES[square_file(to_square)] # Match legal moves. diff --git a/chess/engine.py b/chess/engine.py index 64a3926b7..c961d0da1 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -826,7 +826,7 @@ def get_pipe_transport(self, fd: int) -> Optional[asyncio.BaseTransport]: assert fd == 0, f"expected 0 for stdin, got {fd}" return self - def write(self, data: bytes) -> None: + def write(self, data: bytes | bytearray | memoryview) -> None: self.stdin_buffer.extend(data) while b"\n" in self.stdin_buffer: line_bytes, self.stdin_buffer = self.stdin_buffer.split(b"\n", 1) diff --git a/chess/syzygy.py b/chess/syzygy.py index 77a6eeded..89f8c2596 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -780,6 +780,7 @@ def encode_piece(self, norm: List[int], pos: List[chess.Square], factor: List[in for i in range(n): pos[i] ^= 0x38 + i = 0 for i in range(n): if offdiag(pos[i]): break From c42749dee7e06f1215ad159d58452d571810b8db Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 11:49:05 +0200 Subject: [PATCH 216/250] Make chess.engine.Protocol.options an abstract property --- chess/engine.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index c961d0da1..3f1e0e399 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -852,9 +852,6 @@ def get_returncode(self) -> Optional[int]: class Protocol(asyncio.SubprocessProtocol, metaclass=abc.ABCMeta): """Protocol for communicating with a chess engine process.""" - options: MutableMapping[str, Option] - """Dictionary of available options.""" - id: Dict[str, str] """ Dictionary of information about the engine. Common keys are ``name`` @@ -981,6 +978,11 @@ def __repr__(self) -> str: pid = self.transport.get_pid() if self.transport is not None else "?" return f"<{type(self).__name__} (pid={pid})>" + @property + @abc.abstractmethod + def options(self) -> MutableMapping[str, Option]: + """Dictionary of available options.""" + @abc.abstractmethod async def initialize(self) -> None: """Initializes the engine.""" @@ -1281,7 +1283,7 @@ class UciProtocol(Protocol): def __init__(self) -> None: super().__init__() - self.options: UciOptionMap[Option] = UciOptionMap() + self._options: UciOptionMap[Option] = UciOptionMap() self.config: UciOptionMap[ConfigValue] = UciOptionMap() self.target_config: UciOptionMap[ConfigValue] = UciOptionMap() self.id = {} @@ -1291,6 +1293,11 @@ def __init__(self) -> None: self.may_ponderhit: Optional[chess.Board] = None self.ponderhit = False + @property + @override + def options(self) -> UciOptionMap[Option]: + return self._options + async def initialize(self) -> None: class UciInitializeCommand(BaseCommand[None]): def __init__(self, engine: UciProtocol): @@ -1939,7 +1946,7 @@ def __init__(self) -> None: super().__init__() self.features: Dict[str, Union[int, str]] = {} self.id = {} - self.options = { + self._options = { "random": Option("random", "check", False, None, None, None), "computer": Option("computer", "check", False, None, None, None), "name": Option("name", "string", "", None, None, None), @@ -1953,6 +1960,11 @@ def __init__(self) -> None: self.clock_id: object = None self.first_game = True + @property + @override + def options(self) -> Dict[str, Option]: + return self._options + async def initialize(self) -> None: class XBoardInitializeCommand(BaseCommand[None]): def __init__(self, engine: XBoardProtocol): From 7553d4115f69368e2d7bf07a90773cea128d7d11 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 12:35:01 +0200 Subject: [PATCH 217/250] Make chess.pgn.GameNode pass pyright subtyping check --- chess/pgn.py | 65 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index eddb6bc52..20e95de50 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -16,7 +16,11 @@ from chess import Color, Square if typing.TYPE_CHECKING: - from typing_extensions import Self + from typing_extensions import Self, override +else: + F = typing.TypeVar("F", bound=Callable[..., Any]) + def override(fn: F, /) -> F: + return fn LOGGER = logging.getLogger(__name__) @@ -192,15 +196,6 @@ def __init__(self, node: ChildNode, *, is_variation: bool = False, sidelines: bo class GameNode(abc.ABC): - parent: Optional[GameNode] - """The parent node or ``None`` if this is the root node of the game.""" - - move: Optional[chess.Move] - """ - The move leading to this node or ``None`` if this is the root node of the - game. - """ - variations: List[ChildNode] """A list of child nodes.""" @@ -215,8 +210,6 @@ class GameNode(abc.ABC): nags: Set[int] def __init__(self, *, comment: Union[str, list[str]] = "") -> None: - self.parent = None - self.move = None self.variations = [] self.comments = _standardize_comments(comment) @@ -225,6 +218,19 @@ def __init__(self, *, comment: Union[str, list[str]] = "") -> None: self.starting_comments = [] self.nags = set() + @property + @abc.abstractmethod + def parent(self) -> Optional[GameNode]: + """The parent node or ``None`` if this is the root node of the game.""" + + @property + @abc.abstractmethod + def move(self) -> Optional[chess.Move]: + """ + The move leading to this node or ``None`` if this is the root node of + the game. + """ + @abc.abstractmethod def board(self) -> chess.Board: """ @@ -658,12 +664,6 @@ class ChildNode(GameNode): Extends :class:`~chess.pgn.GameNode`. """ - parent: GameNode - """The parent node.""" - - move: chess.Move - """The move leading to this node.""" - starting_comments: list[str] """ A comment for the start of a variation. Only nodes that @@ -680,13 +680,25 @@ class ChildNode(GameNode): def __init__(self, parent: GameNode, move: chess.Move, *, comment: Union[str, list[str]] = "", starting_comment: Union[str, list[str]] = "", nags: Iterable[int] = []) -> None: super().__init__(comment=comment) - self.parent = parent - self.move = move + self._parent = parent + self._move = move self.parent.variations.append(self) self.nags.update(nags) self.starting_comments = _standardize_comments(starting_comment) + @property + @override + def parent(self) -> GameNode: + """The parent node.""" + return self._parent + + @property + @override + def move(self) -> chess.Move: + """The move leading to this node.""" + return self._move + def board(self) -> chess.Board: stack: List[chess.Move] = [] node: GameNode = self @@ -838,9 +850,21 @@ def __init__(self, headers: Optional[Union[Mapping[str, str], Iterable[Tuple[str self.headers = Headers(headers) self.errors = [] + @property + @override + def parent(self) -> None: + return None + + @property + @override + def move(self) -> None: + return None + + @override def board(self) -> chess.Board: return self.headers.board() + @override def ply(self) -> int: # Optimization: Parse FEN only for custom starting positions. return self.board().ply() if "FEN" in self.headers else 0 @@ -873,6 +897,7 @@ def setup(self, board: Union[chess.Board, str]) -> None: else: self.headers.pop("Variant", None) + @override def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: """ Traverses the game in PGN order using the given *visitor*. Returns From f7736478cbe6e99bb77a7719bfafa79e9a40eef0 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 12:35:28 +0200 Subject: [PATCH 218/250] Initialize board_stack even on skip_game path --- chess/pgn.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chess/pgn.py b/chess/pgn.py index 20e95de50..11d7aa760 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -1575,6 +1575,7 @@ def read_game(handle: TextIO, *, Visitor: Any = GameBuilder) -> Any: skipping_game = False managed_headers: Optional[Headers] = None unmanaged_headers: Optional[Headers] = None + board_stack: List[chess.Board] = [] # Ignore leading empty lines and comments. line = handle.readline().lstrip("\ufeff") From 0c8fed280f5d0ea237dc5a667081665d65412643 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 12:42:13 +0200 Subject: [PATCH 219/250] Fix builder constructor typing --- chess/pgn.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/chess/pgn.py b/chess/pgn.py index 11d7aa760..f40980d48 100644 --- a/chess/pgn.py +++ b/chess/pgn.py @@ -699,6 +699,7 @@ def move(self) -> chess.Move: """The move leading to this node.""" return self._move + @override def board(self) -> chess.Board: stack: List[chess.Move] = [] node: GameNode = self @@ -714,6 +715,7 @@ def board(self) -> chess.Board: return board + @override def ply(self) -> int: ply = 0 node: GameNode = self @@ -744,6 +746,7 @@ def uci(self, *, chess960: Optional[bool] = None) -> str: """ return self.parent.board().uci(self.move, chess960=chess960) + @override def end(self) -> ChildNode: """ Follows the main variation to the end and returns the last node. @@ -801,6 +804,7 @@ def _accept(self, parent_board: chess.Board, visitor: BaseVisitor[ResultT], *, s else: stack.pop() + @override def accept(self, visitor: BaseVisitor[ResultT]) -> ResultT: self._accept(self.parent.board(), visitor, sidelines=False) return visitor.result() @@ -1192,10 +1196,11 @@ class GameBuilder(BaseVisitor[GameT]): @typing.overload def __init__(self: GameBuilder[Game]) -> None: ... @typing.overload - def __init__(self: GameBuilder[GameT], *, Game: Type[GameT]) -> None: ... + def __init__(self, *, Game: Type[GameT]) -> None: ... def __init__(self, *, Game: Any = Game) -> None: self.Game = Game + @override def begin_game(self) -> None: self.game: GameT = self.Game() @@ -1203,28 +1208,35 @@ def begin_game(self) -> None: self.starting_comments: list[str] = [] self.in_variation = False + @override def begin_headers(self) -> Headers: return self.game.headers + @override def visit_header(self, tagname: str, tagvalue: str) -> None: self.game.headers[tagname] = tagvalue + @override def visit_nag(self, nag: int) -> None: self.variation_stack[-1].nags.add(nag) + @override def begin_variation(self) -> None: parent = self.variation_stack[-1].parent assert parent is not None, "begin_variation called, but root node on top of stack" self.variation_stack.append(parent) self.in_variation = False + @override def end_variation(self) -> None: self.variation_stack.pop() + @override def visit_result(self, result: str) -> None: if self.game.headers.get("Result", "*") == "*": self.game.headers["Result"] = result + @override def visit_comment(self, comment: Union[str, list[str]]) -> None: comments = _standardize_comments(comment) if self.in_variation or (self.variation_stack[-1].parent is None and self.variation_stack[-1].is_end()): @@ -1238,12 +1250,14 @@ def visit_comment(self, comment: Union[str, list[str]]) -> None: self.starting_comments.extend(comments) self.starting_comments = list(filter(None, self.starting_comments)) + @override def visit_move(self, board: chess.Board, move: chess.Move) -> None: self.variation_stack[-1] = self.variation_stack[-1].add_variation(move) self.variation_stack[-1].starting_comments = self.starting_comments self.starting_comments = [] self.in_variation = True + @override def handle_error(self, error: Exception) -> None: """ Populates :data:`chess.pgn.Game.errors` with encountered errors and @@ -1277,6 +1291,7 @@ def handle_error(self, error: Exception) -> None: LOGGER.error("%s while parsing %r", error, self.game) self.game.errors.append(error) + @override def result(self) -> GameT: """ Returns the visited :class:`~chess.pgn.Game()`. @@ -1290,20 +1305,24 @@ class HeadersBuilder(BaseVisitor[HeadersT]): @typing.overload def __init__(self: HeadersBuilder[Headers]) -> None: ... @typing.overload - def __init__(self: HeadersBuilder[HeadersT], *, Headers: Type[Headers]) -> None: ... + def __init__(self, *, Headers: Type[HeadersT]) -> None: ... def __init__(self, *, Headers: Any = Headers) -> None: self.Headers = Headers + @override def begin_headers(self) -> HeadersT: self.headers: HeadersT = self.Headers({}) return self.headers + @override def visit_header(self, tagname: str, tagvalue: str) -> None: self.headers[tagname] = tagvalue + @override def end_headers(self) -> SkipType: return SKIP + @override def result(self) -> HeadersT: return self.headers @@ -1314,20 +1333,25 @@ class BoardBuilder(BaseVisitor[chess.Board]): on the move stack. """ + @override def begin_game(self) -> None: self.skip_variation_depth = 0 + @override def begin_variation(self) -> SkipType: self.skip_variation_depth += 1 return SKIP + @override def end_variation(self) -> None: self.skip_variation_depth = max(self.skip_variation_depth - 1, 0) + @override def visit_board(self, board: chess.Board) -> None: if not self.skip_variation_depth: self.board = board + @override def result(self) -> chess.Board: return self.board @@ -1335,15 +1359,19 @@ def result(self) -> chess.Board: class SkipVisitor(BaseVisitor[Literal[True]]): """Skips a game.""" + @override def begin_game(self) -> SkipType: return SKIP + @override def end_headers(self) -> SkipType: return SKIP + @override def begin_variation(self) -> SkipType: return SKIP + @override def result(self) -> Literal[True]: return True @@ -1458,6 +1486,7 @@ class StringExporter(StringExporterMixin, BaseVisitor[str]): There will be no newline characters at the end of the string. """ + @override def result(self) -> str: if self.current_line: return "\n".join(itertools.chain(self.lines, [self.current_line.rstrip()])).rstrip() @@ -1489,6 +1518,7 @@ def __init__(self, handle: TextIO, *, columns: Optional[int] = 80, headers: bool super().__init__(columns=columns, headers=headers, comments=comments, variations=variations) self.handle = handle + @override def begin_game(self) -> None: self.written: int = 0 super().begin_game() @@ -1504,6 +1534,7 @@ def write_line(self, line: str = "") -> None: self.written += self.handle.write(line.rstrip()) self.written += self.handle.write("\n") + @override def result(self) -> int: return self.written From ef13fdbfdb03a10e520a834b32e8a6cac988323a Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 12:44:42 +0200 Subject: [PATCH 220/250] Run pyright in CI --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 576d8b491..ffe0c4bc5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: - run: python examples/perft/perft.py -t 1 --variant horde examples/perft/horde.perft - run: python examples/perft/perft.py -t 1 --variant crazyhouse examples/perft/crazyhouse.perft - run: python examples/perft/perft.py -t 1 --variant 3check examples/perft/3check.perft - mypy: + typing: strategy: matrix: os: [ubuntu-latest, windows-latest] @@ -50,6 +50,9 @@ jobs: - run: pip install mypy - run: python -m mypy --strict chess - run: python -m mypy --strict examples/**/*.py + - run: pip install pyright + - run: python -m pyright chess + - run: python -m pyright --strict examples/**/*.py readme: runs-on: ubuntu-latest steps: From 100b1c8b21846c0a9db2f237621368e02294da5f Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 13 Oct 2024 12:45:44 +0200 Subject: [PATCH 221/250] Fixup pyright usage in CI --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ffe0c4bc5..035b7f3d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -52,7 +52,7 @@ jobs: - run: python -m mypy --strict examples/**/*.py - run: pip install pyright - run: python -m pyright chess - - run: python -m pyright --strict examples/**/*.py + - run: python -m pyright examples/**/*.py readme: runs-on: ubuntu-latest steps: From 4549a1dd5d58661c89ea7a0fd33ae2a3d8e308d8 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 26 Oct 2024 11:36:00 +0200 Subject: [PATCH 222/250] Add 'movesleft' parameter to UCI info parsing --- chess/engine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 3f1e0e399..b979b278f 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -1771,7 +1771,8 @@ def _parse_uci_info(arg: str, root_board: chess.Board, selector: Info = INFO_ALL if parameter == "string": info["string"] = remaining_line break - elif parameter in ["depth", "seldepth", "nodes", "multipv", "currmovenumber", "hashfull", "nps", "tbhits", "cpuload"]: + elif parameter in ["depth", "seldepth", "nodes", "multipv", "currmovenumber", + "hashfull", "nps", "tbhits", "cpuload", "movesleft"]: try: number, remaining_line = _next_token(remaining_line) info[parameter] = int(number) # type: ignore From f1676d51191dbc36cc7d03b4de4da34526e99f88 Mon Sep 17 00:00:00 2001 From: Alexander Lyashuk Date: Sat, 26 Oct 2024 11:41:50 +0200 Subject: [PATCH 223/250] Added a test. --- test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test.py b/test.py index 68904a50e..6db84d254 100755 --- a/test.py +++ b/test.py @@ -3508,14 +3508,15 @@ def test_uci_info(self): self.assertEqual(info["seldepth"], 8) self.assertEqual(info["score"], chess.engine.PovScore(chess.engine.Mate(+3), chess.WHITE)) - # Info: tbhits, cpuload, hashfull, time, nodes, nps. - info = chess.engine._parse_uci_info("tbhits 123 cpuload 456 hashfull 789 time 987 nodes 654 nps 321", board) + # Info: tbhits, cpuload, hashfull, time, nodes, nps, movesleft. + info = chess.engine._parse_uci_info("tbhits 123 cpuload 456 hashfull 789 movesleft 42 time 987 nodes 654 nps 321", board) self.assertEqual(info["tbhits"], 123) self.assertEqual(info["cpuload"], 456) self.assertEqual(info["hashfull"], 789) self.assertEqual(info["time"], 0.987) self.assertEqual(info["nodes"], 654) self.assertEqual(info["nps"], 321) + self.assertEqual(info["movesleft"], 42) # Hakkapeliitta double spaces. info = chess.engine._parse_uci_info("depth 10 seldepth 9 score cp 22 time 17 nodes 48299 nps 2683000 tbhits 0", board) From 518d662e5467c13630cfe98f9b99e720775d80b1 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 9 Nov 2024 13:20:59 +0100 Subject: [PATCH 224/250] Accept a1a1 as UCI null move (used by lc0, closes #1119) --- chess/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/__init__.py b/chess/__init__.py index 4f5791f7c..fdd52ed07 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -705,7 +705,7 @@ def from_uci(cls, uci: str) -> Move: promotion = PIECE_SYMBOLS.index(uci[4]) if len(uci) == 5 else None except ValueError: raise InvalidMoveError(f"invalid uci: {uci!r}") - if from_square == to_square: + if from_square == to_square and from_square != A1: raise InvalidMoveError(f"invalid uci (use 0000 for null moves): {uci!r}") return cls(from_square, to_square, promotion=promotion) else: From 78c765b4dd1741df3a569c3cd96a079d06298823 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 20 Dec 2024 20:25:50 +0100 Subject: [PATCH 225/250] Simplify portable os.O_BINARY access --- chess/polyglot.py | 2 +- chess/syzygy.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/chess/polyglot.py b/chess/polyglot.py index 44a68caa5..a7d6807c4 100644 --- a/chess/polyglot.py +++ b/chess/polyglot.py @@ -324,7 +324,7 @@ class MemoryMappedReader: """Maps a Polyglot opening book to memory.""" def __init__(self, filename: StrOrBytesPath) -> None: - fd = os.open(filename, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) + fd = os.open(filename, os.O_RDONLY | getattr(os, "O_BINARY", 0)) try: self.mmap: Union[mmap.mmap, _EmptyMmap] = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) except (ValueError, OSError): diff --git a/chess/syzygy.py b/chess/syzygy.py index 89f8c2596..5ead9922c 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -587,7 +587,7 @@ def __init__(self, path: str, *, variant: Type[chess.Board] = chess.Board) -> No def init_mmap(self) -> None: if self.data is None: - fd = os.open(self.path, os.O_RDONLY | os.O_BINARY if hasattr(os, "O_BINARY") else os.O_RDONLY) + fd = os.open(self.path, os.O_RDONLY | getattr(os, "O_BINARY", 0)) try: data = mmap.mmap(fd, 0, access=mmap.ACCESS_READ) finally: From ea87e07a22e65bc3b541f2beaefd83e4477d20d1 Mon Sep 17 00:00:00 2001 From: Manan Date: Tue, 31 Dec 2024 18:09:35 +0530 Subject: [PATCH 226/250] Update __init__.py Removed redundant `Generic` import from `chess/__init__.py` --- chess/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/__init__.py b/chess/__init__.py index b01a2e478..8d0a68258 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -22,7 +22,7 @@ import itertools import typing -from typing import ClassVar, Callable, Counter, Dict, Generic, Hashable, Iterable, Iterator, List, Literal, Mapping, Optional, SupportsInt, Tuple, Type, TypeVar, Union +from typing import ClassVar, Callable, Counter, Dict, Hashable, Iterable, Iterator, List, Literal, Mapping, Optional, SupportsInt, Tuple, Type, TypeVar, Union if typing.TYPE_CHECKING: from typing_extensions import Self, TypeAlias From 5f76cb296a10a81672cbf60368a62e2c85adedec Mon Sep 17 00:00:00 2001 From: Adrien Barbaresi Date: Sun, 5 Jan 2025 17:42:33 +0100 Subject: [PATCH 227/250] gaviota.py: simplify and improve code --- chess/gaviota.py | 553 +++++++++++++++-------------------------------- 1 file changed, 179 insertions(+), 374 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 39173b593..8cfd40d1e 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -11,11 +11,12 @@ import struct import typing -import chess - +from itertools import accumulate from types import TracebackType from typing import BinaryIO, Callable, Dict, List, Optional, Tuple, Type, Union +import chess + LOGGER = logging.getLogger(__name__) @@ -109,30 +110,19 @@ def idx_is_empty(x: int) -> int: def flip_type(x: chess.Square, y: chess.Square) -> int: ret = 0 + file_x, rank_x = chess.square_file(x), chess.square_rank(x) + file_y, rank_y = chess.square_file(y), chess.square_rank(y) - if chess.square_file(x) > 3: - x = flip_we(x) - y = flip_we(y) + if file_x > 3: + x, y = flip_we(x), flip_we(y) ret |= 1 - if chess.square_rank(x) > 3: - x = flip_ns(x) - y = flip_ns(y) + if rank_x > 3: + x, y = flip_ns(x), flip_ns(y) ret |= 2 - rowx = chess.square_rank(x) - colx = chess.square_file(x) - - if rowx > colx: - x = flip_nw_se(x) - y = flip_nw_se(y) - ret |= 4 - - rowy = chess.square_rank(y) - coly = chess.square_file(y) - if rowx == colx and rowy > coly: - x = flip_nw_se(x) - y = flip_nw_se(y) + if (rank_x, file_x) > (rank_y, file_y): + x, y = flip_nw_se(x), flip_nw_se(y) ret |= 4 return ret @@ -145,7 +135,6 @@ def init_flipt() -> List[List[int]]: def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: MAX_I = MAX_J = 48 - idx = 0 pp48_idx = [[-1] * MAX_J for _ in range(MAX_I)] pp48_sq_x = [NOSQUARE] * MAX_PP48_INDEX pp48_sq_y = [NOSQUARE] * MAX_PP48_INDEX @@ -157,10 +146,8 @@ def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: j = flip_we(flip_ns(b)) - 8 if idx_is_empty(pp48_idx[i][j]): - pp48_idx[i][j] = idx - pp48_idx[j][i] = idx - pp48_sq_x[idx] = i - pp48_sq_y[idx] = j + pp48_idx[i][j] = pp48_idx[j][i] = idx + pp48_sq_x[idx], pp48_sq_y[idx] = i, j idx += 1 return pp48_idx, pp48_sq_x, pp48_sq_y @@ -179,26 +166,15 @@ def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[ for x in range(48): for y in range(x + 1, 48): for z in range(y + 1, 48): - a = ITOSQ[x] - b = ITOSQ[y] - c = ITOSQ[z] - if not in_queenside(b) or not in_queenside(c): + if not (in_queenside(ITOSQ[y]) and in_queenside(ITOSQ[z])): continue - i = a - 8 - j = b - 8 - k = c - 8 + i, j, k = ITOSQ[x] - 8, ITOSQ[y] - 8, ITOSQ[z] - 8 if idx_is_empty(ppp48_idx[i][j][k]): - ppp48_idx[i][j][k] = idx - ppp48_idx[i][k][j] = idx - ppp48_idx[j][i][k] = idx - ppp48_idx[j][k][i] = idx - ppp48_idx[k][i][j] = idx - ppp48_idx[k][j][i] = idx - ppp48_sq_x[idx] = i - ppp48_sq_y[idx] = j - ppp48_sq_z[idx] = k + for p in [(i, j, k), (i, k, j), (j, i, k), (j, k, i), (k, i, j), (k, j, i)]: + ppp48_idx[p[0]][p[1]][p[2]] = idx + ppp48_sq_x[idx], ppp48_sq_y[idx], ppp48_sq_z[idx] = i, j, k idx += 1 return ppp48_idx, ppp48_sq_x, ppp48_sq_y, ppp48_sq_z @@ -216,8 +192,7 @@ def init_aaidx() -> Tuple[List[int], List[List[int]]]: if idx_is_empty(aaidx[x][y]): # Still empty. - aaidx[x][y] = idx - aaidx[y][x] = idx + aaidx[x][y] = aaidx[y][x] = idx aabase[idx] = x idx += 1 @@ -229,24 +204,10 @@ def init_aaidx() -> Tuple[List[int], List[List[int]]]: def init_aaa() -> Tuple[List[int], List[List[int]]]: # Get aaa_base. comb = [a * (a - 1) // 2 for a in range(64)] - - accum = 0 - aaa_base = [0] * 64 - for a in range(64 - 1): - accum += comb[a] - aaa_base[a + 1] = accum + aaa_base = list(accumulate(comb)) # Get aaa_xyz. - aaa_xyz = [[-1] * 3 for _ in range(MAX_AAAINDEX)] - - idx = 0 - for z in range(64): - for y in range(z): - for x in range(y): - aaa_xyz[idx][0] = x - aaa_xyz[idx][1] = y - aaa_xyz[idx][2] = z - idx += 1 + aaa_xyz = [[x, y, z] for z in range(64) for y in range(z) for x in range(y)] return aaa_base, aaa_xyz @@ -351,34 +312,33 @@ def init_ppidx() -> Tuple[List[List[int]], List[int], List[int]]: def norm_kkindex(x: chess.Square, y: chess.Square) -> Tuple[int, int]: - if chess.square_file(x) > 3: - x = flip_we(x) - y = flip_we(y) + file_x, rank_x = chess.square_file(x), chess.square_rank(x) + + if file_x > 3: + x, y = flip_we(x), flip_we(y) - if chess.square_rank(x) > 3: - x = flip_ns(x) - y = flip_ns(y) + if rank_x > 3: + x, y = flip_ns(x), flip_ns(y) rowx = chess.square_rank(x) colx = chess.square_file(x) if rowx > colx: - x = flip_nw_se(x) - y = flip_nw_se(y) + x, y = flip_nw_se(x), flip_nw_se(y) rowy = chess.square_rank(y) coly = chess.square_file(y) if rowx == colx and rowy > coly: - x = flip_nw_se(x) - y = flip_nw_se(y) + x, y = flip_nw_se(x), flip_nw_se(y) return x, y + def init_kkidx() -> Tuple[List[List[int]], List[int], List[int]]: kkidx = [[-1] * 64 for _ in range(64)] - bksq = [-1] * MAX_KKINDEX - wksq = [-1] * MAX_KKINDEX + bksq, wksq = [-1] * MAX_KKINDEX, [-1] * MAX_KKINDEX + idx = 0 for x in range(64): for y in range(64): @@ -388,10 +348,8 @@ def init_kkidx() -> Tuple[List[List[int]], List[int], List[int]]: i, j = norm_kkindex(x, y) if idx_is_empty(kkidx[i][j]): - kkidx[i][j] = idx - kkidx[x][y] = idx - bksq[idx] = i - wksq[idx] = j + kkidx[i][j] = kkidx[x][y] = idx + bksq[idx], wksq[idx] = i, j idx += 1 return kkidx, wksq, bksq @@ -404,20 +362,12 @@ def kxk_pctoindex(c: Request) -> int: ft = flip_type(c.black_piece_squares[0], c.white_piece_squares[0]) - ws = c.white_piece_squares - bs = c.black_piece_squares - - if (ft & 1) != 0: - ws = [flip_we(b) for b in ws] - bs = [flip_we(b) for b in bs] - - if (ft & 2) != 0: - ws = [flip_ns(b) for b in ws] - bs = [flip_ns(b) for b in bs] + ws, bs = c.white_piece_squares, c.black_piece_squares - if (ft & 4) != 0: - ws = [flip_nw_se(b) for b in ws] - bs = [flip_nw_se(b) for b in bs] + for f, flip in [(1, flip_we), (2, flip_ns), (4, flip_nw_se)]: + if ft & f: + ws = [flip(b) for b in ws] + bs = [flip(b) for b in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] @@ -426,6 +376,14 @@ def kxk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] + +def flip_we_col(*pieces: int) -> tuple[int, ...]: + if (pieces[0] & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + pieces = tuple(flip_we(piece) for piece in pieces) + return pieces + + def kapkb_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 * 64 BLOCK_B = 64 * 64 * 64 @@ -438,24 +396,17 @@ def kapkb_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] ba = c.black_piece_squares[1] - if not (chess.A2 <= pawn < chess.A8): + if not chess.A2 <= pawn < chess.A8: return NOINDEX - if (pawn & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) - ba = flip_we(ba) + pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) - sq = pawn - sq ^= 56 # flip_ns - sq -= 8 # Down one row - pslice = (sq + (sq & 3)) >> 1 + # flip_ns, down one row + pslice = ((pawn ^ 56) - 8 + (pawn & 3)) >> 1 return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa * BLOCK_D + ba + def kabpk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 * 64 BLOCK_B = 64 * 64 * 64 @@ -468,18 +419,13 @@ def kabpk_pctoindex(c: Request) -> int: pawn = c.white_piece_squares[3] bk = c.black_piece_squares[0] - if (pawn & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) - wb = flip_we(wb) + pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) pslice = wsq_to_pidx24(pawn) return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa * BLOCK_D + wb + def kabkp_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 * 64 BLOCK_B = 64 * 64 * 64 @@ -492,23 +438,17 @@ def kabkp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] wb = c.white_piece_squares[2] - if not (chess.A2 <= pawn < chess.A8): + if not chess.A2 <= pawn < chess.A8: return NOINDEX - if (pawn & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) - wb = flip_we(wb) + pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) - sq = pawn - sq -= 8 # Down one row - pslice = (sq + (sq & 3)) >> 1 + # Down one row + pslice = ((pawn - 8) + (pawn & 3)) >> 1 return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa * BLOCK_D + wb + def kaapk_pctoindex(c: Request) -> int: BLOCK_C = MAX_AAINDEX BLOCK_B = 64 * BLOCK_C @@ -520,13 +460,7 @@ def kaapk_pctoindex(c: Request) -> int: pawn = c.white_piece_squares[3] bk = c.black_piece_squares[0] - if (pawn & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) - wa2 = flip_we(wa2) + pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) pslice = wsq_to_pidx24(pawn) @@ -537,6 +471,7 @@ def kaapk_pctoindex(c: Request) -> int: return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + aa_combo + def kaakp_pctoindex(c: Request) -> int: BLOCK_C = MAX_AAINDEX BLOCK_B = 64 * BLOCK_C @@ -548,13 +483,7 @@ def kaakp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] pawn = c.black_piece_squares[1] - if (pawn & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) - wa2 = flip_we(wa2) + pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) pawn = flip_ns(pawn) pslice = wsq_to_pidx24(pawn) @@ -566,6 +495,7 @@ def kaakp_pctoindex(c: Request) -> int: return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + aa_combo + def kapkp_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 BLOCK_B = 64 * 64 @@ -573,30 +503,20 @@ def kapkp_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] wa = c.white_piece_squares[1] - pawn_a = c.white_piece_squares[2] + anchor = c.white_piece_squares[2] bk = c.black_piece_squares[0] - pawn_b = c.black_piece_squares[1] - - anchor = pawn_a - loosen = pawn_b + loosen = c.black_piece_squares[1] - if (anchor & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - anchor = flip_we(anchor) - loosen = flip_we(loosen) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) + anchor, loosen, wk, bk, wa = flip_we_col(anchor, loosen, wk, bk, wa) - m = wsq_to_pidx24(anchor) - n = loosen - 8 - pp_slice = m * 48 + n + pp_slice = wsq_to_pidx24(anchor) * 48 + loosen - 8 if idx_is_empty(pp_slice): return NOINDEX return pp_slice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa + def kappk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 BLOCK_B = 64 * 64 @@ -610,13 +530,7 @@ def kappk_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - if (anchor & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - anchor = flip_we(anchor) - loosen = flip_we(loosen) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) + anchor, loosen, wk, bk, wa = flip_we_col(anchor, loosen, wk, bk, wa) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) @@ -628,6 +542,7 @@ def kappk_pctoindex(c: Request) -> int: return pp_slice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa + def kppka_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 BLOCK_B = 64 * 64 @@ -641,12 +556,7 @@ def kppka_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - if (anchor & 7) > 3: - anchor = flip_we(anchor) - loosen = flip_we(loosen) - wk = flip_we(wk) - bk = flip_we(bk) - ba = flip_we(ba) + anchor, loosen, wk, bk, wa = flip_we_col(anchor, loosen, wk, bk, wa) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) @@ -658,6 +568,7 @@ def kppka_pctoindex(c: Request) -> int: return pp_slice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + ba + def kabck_pctoindex(c: Request) -> int: N_WHITE = 4 N_BLACK = 1 @@ -689,6 +600,7 @@ def kabck_pctoindex(c: Request) -> int: return ki * BLOCK_A + ws[1] * BLOCK_B + ws[2] * BLOCK_C + ws[3] + def kabbk_pctoindex(c: Request) -> int: N_WHITE = 4 N_BLACK = 1 @@ -720,6 +632,7 @@ def kabbk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai * BLOCK_Bx + ws[1] + def kaabk_pctoindex(c: Request) -> int: N_WHITE = 4 N_BLACK = 1 @@ -751,45 +664,23 @@ def kaabk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai * BLOCK_Bx + ws[3] + def aaa_getsubi(x: int, y: int, z: int) -> int: - bse = AAA_BASE[z] - calc_idx = x + (y - 1) * y // 2 + bse - return calc_idx + return x + (y - 1) * y // 2 + AAA_BASE[z] + def kaaak_pctoindex(c: Request) -> int: - N_WHITE = 4 - N_BLACK = 1 BLOCK_Ax = MAX_AAAINDEX - - ws = c.white_piece_squares[:N_WHITE] - bs = c.black_piece_squares[:N_BLACK] - + ws = c.white_piece_squares[:4] + bs = c.black_piece_squares[:1] ft = FLIPT[c.black_piece_squares[0]][c.white_piece_squares[0]] - if (ft & WE_FLAG) != 0: - ws = [flip_we(i) for i in ws] - bs = [flip_we(i) for i in bs] - - if (ft & NS_FLAG) != 0: - ws = [flip_ns(i) for i in ws] - bs = [flip_ns(i) for i in bs] + for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: + if ft & flag: + ws = [flip(i) for i in ws] + bs = [flip(i) for i in bs] - if (ft & NW_SE_FLAG) != 0: - ws = [flip_nw_se(i) for i in ws] - bs = [flip_nw_se(i) for i in bs] - - if ws[2] < ws[1]: - tmp = ws[1] - ws[1] = ws[2] - ws[2] = tmp - if ws[3] < ws[2]: - tmp = ws[2] - ws[2] = ws[3] - ws[3] = tmp - if ws[2] < ws[1]: - tmp = ws[1] - ws[1] = ws[2] - ws[2] = tmp + ws[1:4] = sorted(ws[1:4]) ki = KKIDX[bs[0]][ws[0]] @@ -803,6 +694,7 @@ def kaaak_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai + def kppkp_pctoindex(c: Request) -> int: BLOCK_Ax = MAX_PP48_INDEX * 64 * 64 BLOCK_Bx = 64 * 64 @@ -814,12 +706,7 @@ def kppkp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] pawn_c = c.black_piece_squares[1] - if (pawn_c & 7) > 3: - wk = flip_we(wk) - pawn_a = flip_we(pawn_a) - pawn_b = flip_we(pawn_b) - bk = flip_we(bk) - pawn_c = flip_we(pawn_c) + pawn_c, wk, pawn_a, pawn_b, bk = flip_we_col(pawn_c, wk, pawn_a, pawn_b, bk) i = flip_we(flip_ns(pawn_a)) - 8 j = flip_we(flip_ns(pawn_b)) - 8 @@ -834,28 +721,19 @@ def kppkp_pctoindex(c: Request) -> int: return k * BLOCK_Ax + pp48_slice * BLOCK_Bx + wk * BLOCK_Cx + bk + def kaakb_pctoindex(c: Request) -> int: - N_WHITE = 3 - N_BLACK = 2 BLOCK_Bx = 64 BLOCK_Ax = BLOCK_Bx * MAX_AAINDEX + ws = c.white_piece_squares[:3] + bs = c.black_piece_squares[:2] ft = FLIPT[c.black_piece_squares[0]][c.white_piece_squares[0]] - ws = c.white_piece_squares[:N_WHITE] - bs = c.black_piece_squares[:N_BLACK] - - if (ft & WE_FLAG) != 0: - ws = [flip_we(i) for i in ws] - bs = [flip_we(i) for i in bs] - - if (ft & NS_FLAG) != 0: - ws = [flip_ns(i) for i in ws] - bs = [flip_ns(i) for i in bs] - - if (ft & NW_SE_FLAG) != 0: - ws = [flip_nw_se(i) for i in ws] - bs = [flip_nw_se(i) for i in bs] + for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: + if ft & flag: + ws = [flip(i) for i in ws] + bs = [flip(i) for i in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] ai = AAIDX[ws[1]][ws[2]] @@ -865,6 +743,7 @@ def kaakb_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai * BLOCK_Bx + bs[1] + def kabkc_pctoindex(c: Request) -> int: N_WHITE = 3 N_BLACK = 2 @@ -878,17 +757,10 @@ def kabkc_pctoindex(c: Request) -> int: ws = c.white_piece_squares[:N_WHITE] bs = c.black_piece_squares[:N_BLACK] - if (ft & WE_FLAG) != 0: - ws = [flip_we(i) for i in ws] - bs = [flip_we(i) for i in bs] - - if (ft & NS_FLAG) != 0: - ws = [flip_ns(i) for i in ws] - bs = [flip_ns(i) for i in bs] - - if (ft & NW_SE_FLAG) != 0: - ws = [flip_nw_se(i) for i in ws] - bs = [flip_nw_se(i) for i in bs] + for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: + if ft & flag: + ws = [flip(i) for i in ws] + bs = [flip(i) for i in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX [black king] [white king] @@ -897,23 +769,17 @@ def kabkc_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] * BLOCK_Bx + ws[2] * BLOCK_Cx + bs[1] + def kpkp_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - pawn_a = c.white_piece_squares[1] - pawn_b = c.black_piece_squares[1] + anchor = c.white_piece_squares[1] + loosen = c.black_piece_squares[1] - anchor = pawn_a - loosen = pawn_b - - if (anchor & 7) > 3: - anchor = flip_we(anchor) - loosen = flip_we(loosen) - wk = flip_we(wk) - bk = flip_we(bk) + anchor, loosen, wk, bk = flip_we_col(anchor, loosen, wk, bk) m = wsq_to_pidx24(anchor) n = loosen - 8 @@ -925,6 +791,7 @@ def kpkp_pctoindex(c: Request) -> int: return pp_slice * BLOCK_Ax + wk * BLOCK_Bx + bk + def kppk_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 @@ -935,11 +802,7 @@ def kppk_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - if (anchor & 7) > 3: - anchor = flip_we(anchor) - loosen = flip_we(loosen) - wk = flip_we(wk) - bk = flip_we(bk) + anchor, loosen, wk, bk = flip_we_col(anchor, loosen, wk, bk) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) @@ -951,6 +814,7 @@ def kppk_pctoindex(c: Request) -> int: return pp_slice * BLOCK_Ax + wk * BLOCK_Bx + bk + def kapk_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 * 64 BLOCK_Bx = 64 * 64 @@ -961,22 +825,17 @@ def kapk_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - if not (chess.A2 <= pawn < chess.A8): + if not chess.A2 <= pawn < chess.A8: return NOINDEX - if (pawn & 7) > 3: - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) + pawn, wk, bk, wa = flip_we_col(pawn, wk, bk, wa) - sq = pawn - sq ^= 56 # flip_ns - sq -= 8 # Down one row + sq = pawn ^ 56 - 8 # flip_ns and down one row pslice = ((sq + (sq & 3)) >> 1) return pslice * BLOCK_Ax + wk * BLOCK_Bx + bk * BLOCK_Cx + wa + def kabk_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 @@ -986,17 +845,10 @@ def kabk_pctoindex(c: Request) -> int: ws = c.white_piece_squares bs = c.black_piece_squares - if (ft & 1) != 0: - ws = [flip_we(b) for b in ws] - bs = [flip_we(b) for b in bs] - - if (ft & 2) != 0: - ws = [flip_ns(b) for b in ws] - bs = [flip_ns(b) for b in bs] - - if (ft & 4) != 0: - ws = [flip_nw_se(b) for b in ws] - bs = [flip_nw_se(b) for b in bs] + for flag, flip in [(1, flip_we), (2, flip_ns), (4, flip_nw_se)]: + if ft & flag: + ws = [flip(b) for b in ws] + bs = [flip(b) for b in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] @@ -1005,6 +857,7 @@ def kabk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] * BLOCK_Bx + ws[2] + def kakp_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 * 64 BLOCK_Bx = 64 * 64 @@ -1015,42 +868,29 @@ def kakp_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - if not (chess.A2 <= pawn < chess.A8): + if not chess.A2 <= pawn < chess.A8: return NOINDEX - if (pawn & 7) > 3: - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) - wa = flip_we(wa) + pawn, wk, bk, wa = flip_we_col(pawn, wk, bk, wa) - sq = pawn - sq -= 8 # Down one row - pslice = (sq + (sq & 3)) >> 1 + # Down one row + pslice = ((pawn - 8) + ((pawn - 8) & 3)) >> 1 return pslice * BLOCK_Ax + wk * BLOCK_Bx + bk * BLOCK_Cx + wa + def kaak_pctoindex(c: Request) -> int: - N_WHITE = 3 - N_BLACK = 1 BLOCK_Ax = MAX_AAINDEX ft = FLIPT[c.black_piece_squares[0]][c.white_piece_squares[0]] - ws = c.white_piece_squares[:N_WHITE] - bs = c.black_piece_squares[:N_BLACK] - - if (ft & WE_FLAG) != 0: - ws = [flip_we(i) for i in ws] - bs = [flip_we(i) for i in bs] + ws = c.white_piece_squares[:3] + bs = c.black_piece_squares[:1] - if (ft & NS_FLAG) != 0: - ws = [flip_ns(i) for i in ws] - bs = [flip_ns(i) for i in bs] - - if (ft & NW_SE_FLAG) != 0: - ws = [flip_nw_se(i) for i in ws] - bs = [flip_nw_se(i) for i in bs] + for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: + if ft & flag: + ws = [flip(i) for i in ws] + bs = [flip(i) for i in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] ai = AAIDX[ws[1]][ws[2]] @@ -1060,6 +900,7 @@ def kaak_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai + def kakb_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 @@ -1069,23 +910,9 @@ def kakb_pctoindex(c: Request) -> int: ws = c.white_piece_squares[:] bs = c.black_piece_squares[:] - if (ft & 1) != 0: - ws[0] = flip_we(ws[0]) - ws[1] = flip_we(ws[1]) - bs[0] = flip_we(bs[0]) - bs[1] = flip_we(bs[1]) - - if (ft & 2) != 0: - ws[0] = flip_ns(ws[0]) - ws[1] = flip_ns(ws[1]) - bs[0] = flip_ns(bs[0]) - bs[1] = flip_ns(bs[1]) - - if (ft & 4) != 0: - ws[0] = flip_nw_se(ws[0]) - ws[1] = flip_nw_se(ws[1]) - bs[0] = flip_nw_se(bs[0]) - bs[1] = flip_nw_se(bs[1]) + for bit, flip in [(1, flip_we), (2, flip_ns), (4, flip_nw_se)]: + if ft & bit: + ws[0], ws[1], bs[0], bs[1] = flip(ws[0]), flip(ws[1]), flip(bs[0]), flip(bs[1]) ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] @@ -1094,6 +921,7 @@ def kakb_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] * BLOCK_Bx + bs[1] + def kpk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 BLOCK_B = 64 @@ -1102,21 +930,16 @@ def kpk_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - if not (chess.A2 <= pawn < chess.A8): + if not chess.A2 <= pawn < chess.A8: return NOINDEX - if (pawn & 7) > 3: - pawn = flip_we(pawn) - wk = flip_we(wk) - bk = flip_we(bk) + pawn, wk, bk = flip_we_col(pawn, wk, bk) - sq = pawn - sq ^= 56 # flip_ns - sq -= 8 # Down one row + sq = (pawn ^ 56) - 8 # flip_ns, down one row pslice = ((sq + (sq & 3)) >> 1) - res = pslice * BLOCK_A + wk * BLOCK_B + bk - return res + return pslice * BLOCK_A + wk * BLOCK_B + bk + def kpppk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 @@ -1126,26 +949,16 @@ def kpppk_pctoindex(c: Request) -> int: pawn_a = c.white_piece_squares[1] pawn_b = c.white_piece_squares[2] pawn_c = c.white_piece_squares[3] - bk = c.black_piece_squares[0] - i = pawn_a - 8 - j = pawn_b - 8 - k = pawn_c - 8 - + i, j, k = [x - 8 for x in (pawn_a, pawn_b, pawn_c)] ppp48_slice = PPP48_IDX[i][j][k] if idx_is_empty(ppp48_slice): - wk = flip_we(wk) - pawn_a = flip_we(pawn_a) - pawn_b = flip_we(pawn_b) - pawn_c = flip_we(pawn_c) - bk = flip_we(bk) - - i = pawn_a - 8 - j = pawn_b - 8 - k = pawn_c - 8 + wk, pawn_a, pawn_b, pawn_c, bk = [flip_we(x) for x in (wk, pawn_a, pawn_b, pawn_c, bk)] + # removing this doesn't impact the tests? + i, j, k = [x - 8 for x in (pawn_a, pawn_b, pawn_c)] ppp48_slice = PPP48_IDX[i][j][k] if idx_is_empty(ppp48_slice): @@ -1330,13 +1143,15 @@ def __init__(self, maxindex: int, slice_n: int, pctoi: Callable[[Request], int]) def sortlists(ws: List[int], wp: List[int]) -> Tuple[List[int], List[int]]: - z = sorted(zip(wp, ws), key=lambda x: x[0], reverse=True) + z = sorted(zip(wp, ws), reverse=True) wp2, ws2 = zip(*z) return list(ws2), list(wp2) + def egtb_block_unpack(side: int, n: int, bp: bytes) -> List[int]: return [dtm_unpack(side, i) for i in bp[:n]] + def split_index(i: int) -> Tuple[int, int]: return divmod(i, ENTRIES_PER_BLOCK) @@ -1360,19 +1175,23 @@ def removepiece(ys: List[int], yp: List[int], j: int) -> None: del ys[j] del yp[j] + def opp(side: int) -> int: return 1 if side == 0 else 0 -def adjust_up(dist: int) -> int: - udist = dist - sw = udist & INFOMASK - if sw in [iWMATE, iWMATEt, iBMATE, iBMATEt]: - udist += (1 << PLYSHIFT) +def adjust_up(dist: int) -> int: + if (dist & INFOMASK) in [iWMATE, iWMATEt, iBMATE, iBMATEt]: + return dist + (1 << PLYSHIFT) + return dist - return udist def bestx(side: int, a: int, b: int) -> int: + if a == iFORBID: + return b + if b == iFORBID: + return a + # 0 = selectfirst # 1 = selectlowest # 2 = selecthighest @@ -1385,33 +1204,25 @@ def bestx(side: int, a: int, b: int) -> int: [3, 3, 3, 0], # forbid ] - xorkey = [0, 3] - - if a == iFORBID: - return b - if b == iFORBID: - return a - retu = [a, a, b, b] if b < a: - retu[1] = b - retu[2] = a + retu[1:2] = [b, a] - key = comparison[a & 3][b & 3] ^ xorkey[side] + key = comparison[a & 3][b & 3] ^ [0, 3][side] # ^ xorkey return retu[key] + def unpackdist(d: int) -> Tuple[int, int]: return d >> PLYSHIFT, d & INFOMASK -def dtm_unpack(stm: int, packed: int) -> int: - p = packed - if p in [iDRAW, iFORBID]: - return p +def dtm_unpack(stm: int, packed: int) -> int: + if packed in [iDRAW, iFORBID]: + return packed - info = p & 3 - store = p >> 2 + info = packed & 3 + store = packed >> 2 if stm == 0: if info == iWMATE: @@ -1587,28 +1398,23 @@ def probe_dtm(self, board: chess.Board) -> int: if req.realside == 1: if req.is_reversed: return ply - else: - return -ply - else: - if req.is_reversed: - return -ply - else: - return ply - elif res == iBMATE: + return -ply + if req.is_reversed: + return -ply + return ply + + if res == iBMATE: # Black mates in the stored position. if req.realside == 0: if req.is_reversed: return ply - else: - return -ply - else: - if req.is_reversed: - return -ply - else: - return ply - else: - # Draw. - return 0 + return -ply + if req.is_reversed: + return -ply + return ply + + # Draw. + return 0 def get_dtm(self, board: chess.Board, default: Optional[int] = None) -> Optional[int]: try: @@ -1644,12 +1450,12 @@ def probe_wdl(self, board: chess.Board) -> int: if dtm == 0: if board.is_checkmate(): return -1 - else: - return 0 - elif dtm > 0: + return 0 + + if dtm > 0: return 1 - else: - return -1 + + return -1 def get_wdl(self, board: chess.Board, default: Optional[int] = None) -> Optional[int]: try: @@ -1795,8 +1601,7 @@ def egtb_block_getsize(self, req: Request, idx: int) -> int: if (offset + blocksz) > maxindex: return maxindex - offset # Last block size - else: - return blocksz # Size of a normal block + return blocksz # Size of a normal block def _tb_probe(self, req: Request) -> int: stream = self._setup_tablebase(req) From 4849537943da0cf3aa839770af2fa9f4c1432424 Mon Sep 17 00:00:00 2001 From: Adrien Barbaresi Date: Sun, 5 Jan 2025 17:49:53 +0100 Subject: [PATCH 228/250] fix mypy errors --- chess/gaviota.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 8cfd40d1e..9abe11bcb 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -419,7 +419,7 @@ def kabpk_pctoindex(c: Request) -> int: pawn = c.white_piece_squares[3] bk = c.black_piece_squares[0] - pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) + pawn, wk, bk, wa, wb = flip_we_col(pawn, wk, bk, wa, wb) pslice = wsq_to_pidx24(pawn) @@ -441,7 +441,7 @@ def kabkp_pctoindex(c: Request) -> int: if not chess.A2 <= pawn < chess.A8: return NOINDEX - pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) + pawn, wk, bk, wa, wb = flip_we_col(pawn, wk, bk, wa, wb) # Down one row pslice = ((pawn - 8) + (pawn & 3)) >> 1 @@ -460,7 +460,7 @@ def kaapk_pctoindex(c: Request) -> int: pawn = c.white_piece_squares[3] bk = c.black_piece_squares[0] - pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) + pawn, wk, bk, wa, wa2 = flip_we_col(pawn, wk, bk, wa, wa2) pslice = wsq_to_pidx24(pawn) @@ -483,7 +483,7 @@ def kaakp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] pawn = c.black_piece_squares[1] - pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) + pawn, wk, bk, wa, wa2 = flip_we_col(pawn, wk, bk, wa, wa2) pawn = flip_ns(pawn) pslice = wsq_to_pidx24(pawn) @@ -556,7 +556,7 @@ def kppka_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - anchor, loosen, wk, bk, wa = flip_we_col(anchor, loosen, wk, bk, wa) + anchor, loosen, wk, bk, ba = flip_we_col(anchor, loosen, wk, bk, ba) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) From 08b6647d6fd5b6a512bbc9e1ab50222073f697bc Mon Sep 17 00:00:00 2001 From: Adrien Barbaresi Date: Mon, 6 Jan 2025 13:59:45 +0100 Subject: [PATCH 229/250] add permutations --- chess/gaviota.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 9abe11bcb..a3372f04e 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -11,7 +11,7 @@ import struct import typing -from itertools import accumulate +from itertools import accumulate, permutations from types import TracebackType from typing import BinaryIO, Callable, Dict, List, Optional, Tuple, Type, Union @@ -172,8 +172,8 @@ def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[ i, j, k = ITOSQ[x] - 8, ITOSQ[y] - 8, ITOSQ[z] - 8 if idx_is_empty(ppp48_idx[i][j][k]): - for p in [(i, j, k), (i, k, j), (j, i, k), (j, k, i), (k, i, j), (k, j, i)]: - ppp48_idx[p[0]][p[1]][p[2]] = idx + for ii, jj, kk in permutations((i, j, k)): + ppp48_idx[ii][jj][kk] = idx ppp48_sq_x[idx], ppp48_sq_y[idx], ppp48_sq_z[idx] = i, j, k idx += 1 From bbf2a05e6b6e3a83651b4333584940bc652cdea2 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Wed, 8 Jan 2025 20:30:04 +0100 Subject: [PATCH 230/250] Update source of Gaviota tables --- data/gaviota/SOURCE.txt | 290 +++++++++++++++++------------------ data/gaviota/TEST-SOURCE.txt | 94 ++++++------ 2 files changed, 192 insertions(+), 192 deletions(-) diff --git a/data/gaviota/SOURCE.txt b/data/gaviota/SOURCE.txt index dda9c83c7..706756322 100644 --- a/data/gaviota/SOURCE.txt +++ b/data/gaviota/SOURCE.txt @@ -1,145 +1,145 @@ -https://syzygy-tables.info/gaviota/kbk.gtb.cp4 -https://syzygy-tables.info/gaviota/knk.gtb.cp4 -https://syzygy-tables.info/gaviota/kpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqk.gtb.cp4 -https://syzygy-tables.info/gaviota/krk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kbkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kbkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpk.gtb.cp4 -https://syzygy-tables.info/gaviota/knkn.gtb.cp4 -https://syzygy-tables.info/gaviota/knkp.gtb.cp4 -https://syzygy-tables.info/gaviota/knnk.gtb.cp4 -https://syzygy-tables.info/gaviota/knpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kppk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrk.gtb.cp4 -https://syzygy-tables.info/gaviota/krbk.gtb.cp4 -https://syzygy-tables.info/gaviota/krkb.gtb.cp4 -https://syzygy-tables.info/gaviota/krkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krkr.gtb.cp4 -https://syzygy-tables.info/gaviota/krnk.gtb.cp4 -https://syzygy-tables.info/gaviota/krpk.gtb.cp4 -https://syzygy-tables.info/gaviota/krrk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbbpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kbppk.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkb.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkn.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkp.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkq.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkr.gtb.cp4 -https://syzygy-tables.info/gaviota/knnnk.gtb.cp4 -https://syzygy-tables.info/gaviota/knnpk.gtb.cp4 -https://syzygy-tables.info/gaviota/knpkb.gtb.cp4 -https://syzygy-tables.info/gaviota/knpkn.gtb.cp4 -https://syzygy-tables.info/gaviota/knpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/knpkq.gtb.cp4 -https://syzygy-tables.info/gaviota/knpkr.gtb.cp4 -https://syzygy-tables.info/gaviota/knppk.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kpppk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqppk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqqk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqrk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrrk.gtb.cp4 -https://syzygy-tables.info/gaviota/krbbk.gtb.cp4 -https://syzygy-tables.info/gaviota/krbkb.gtb.cp4 -https://syzygy-tables.info/gaviota/krbkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krbkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krbkq.gtb.cp4 -https://syzygy-tables.info/gaviota/krbkr.gtb.cp4 -https://syzygy-tables.info/gaviota/krbnk.gtb.cp4 -https://syzygy-tables.info/gaviota/krbpk.gtb.cp4 -https://syzygy-tables.info/gaviota/krnkb.gtb.cp4 -https://syzygy-tables.info/gaviota/krnkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krnkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krnkq.gtb.cp4 -https://syzygy-tables.info/gaviota/krnkr.gtb.cp4 -https://syzygy-tables.info/gaviota/krnnk.gtb.cp4 -https://syzygy-tables.info/gaviota/krnpk.gtb.cp4 -https://syzygy-tables.info/gaviota/krpkb.gtb.cp4 -https://syzygy-tables.info/gaviota/krpkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krpkq.gtb.cp4 -https://syzygy-tables.info/gaviota/krpkr.gtb.cp4 -https://syzygy-tables.info/gaviota/krppk.gtb.cp4 -https://syzygy-tables.info/gaviota/krrbk.gtb.cp4 -https://syzygy-tables.info/gaviota/krrkb.gtb.cp4 -https://syzygy-tables.info/gaviota/krrkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krrkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krrkq.gtb.cp4 -https://syzygy-tables.info/gaviota/krrkr.gtb.cp4 -https://syzygy-tables.info/gaviota/krrnk.gtb.cp4 -https://syzygy-tables.info/gaviota/krrpk.gtb.cp4 -https://syzygy-tables.info/gaviota/krrrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kpppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqqk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrrk.gtb.cp4 diff --git a/data/gaviota/TEST-SOURCE.txt b/data/gaviota/TEST-SOURCE.txt index f7d29a546..36c83d39a 100644 --- a/data/gaviota/TEST-SOURCE.txt +++ b/data/gaviota/TEST-SOURCE.txt @@ -1,47 +1,47 @@ -https://syzygy-tables.info/gaviota/kbbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kbkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kbkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpk.gtb.cp4 -https://syzygy-tables.info/gaviota/knkn.gtb.cp4 -https://syzygy-tables.info/gaviota/knkp.gtb.cp4 -https://syzygy-tables.info/gaviota/knnk.gtb.cp4 -https://syzygy-tables.info/gaviota/knpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kppk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkb.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkq.gtb.cp4 -https://syzygy-tables.info/gaviota/kqkr.gtb.cp4 -https://syzygy-tables.info/gaviota/kqnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqpk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqqk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrk.gtb.cp4 -https://syzygy-tables.info/gaviota/krbk.gtb.cp4 -https://syzygy-tables.info/gaviota/krkb.gtb.cp4 -https://syzygy-tables.info/gaviota/krkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krkr.gtb.cp4 -https://syzygy-tables.info/gaviota/krnk.gtb.cp4 -https://syzygy-tables.info/gaviota/krpk.gtb.cp4 -https://syzygy-tables.info/gaviota/krrk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqrnk.gtb.cp4 -https://syzygy-tables.info/gaviota/krpkn.gtb.cp4 -https://syzygy-tables.info/gaviota/kbpkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krrpk.gtb.cp4 -https://syzygy-tables.info/gaviota/knppk.gtb.cp4 -https://syzygy-tables.info/gaviota/kbnkb.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkn.gtb.cp4 -https://syzygy-tables.info/gaviota/krrnk.gtb.cp4 -https://syzygy-tables.info/gaviota/kqbbk.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kppkq.gtb.cp4 -https://syzygy-tables.info/gaviota/krrrk.gtb.cp4 -https://syzygy-tables.info/gaviota/krnkp.gtb.cp4 -https://syzygy-tables.info/gaviota/kpppk.gtb.cp4 -https://syzygy-tables.info/gaviota/knnkp.gtb.cp4 -https://syzygy-tables.info/gaviota/krnpk.gtb.cp4 -https://syzygy-tables.info/gaviota/knpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqqk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krkr.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqrnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krpkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbpkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kbnkb.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkn.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrnk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kqbbk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kppkq.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krrrk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/kpppk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knnkp.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/krnpk.gtb.cp4 +https://tablebase.lichess.ovh/tables/standard/Gaviota/knpkp.gtb.cp4 From 3a974697b31e39ea8ad7e115350dc190464d7a76 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 11 Jan 2025 15:50:27 +0100 Subject: [PATCH 231/250] Use import from only for types --- chess/gaviota.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index a3372f04e..0bbe41b81 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -4,6 +4,7 @@ import ctypes.util import dataclasses import fnmatch +import itertools import logging import lzma import os @@ -11,7 +12,6 @@ import struct import typing -from itertools import accumulate, permutations from types import TracebackType from typing import BinaryIO, Callable, Dict, List, Optional, Tuple, Type, Union @@ -172,7 +172,7 @@ def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[ i, j, k = ITOSQ[x] - 8, ITOSQ[y] - 8, ITOSQ[z] - 8 if idx_is_empty(ppp48_idx[i][j][k]): - for ii, jj, kk in permutations((i, j, k)): + for ii, jj, kk in itertools.permutations((i, j, k)): ppp48_idx[ii][jj][kk] = idx ppp48_sq_x[idx], ppp48_sq_y[idx], ppp48_sq_z[idx] = i, j, k idx += 1 @@ -204,7 +204,7 @@ def init_aaidx() -> Tuple[List[int], List[List[int]]]: def init_aaa() -> Tuple[List[int], List[List[int]]]: # Get aaa_base. comb = [a * (a - 1) // 2 for a in range(64)] - aaa_base = list(accumulate(comb)) + aaa_base = list(itertools.accumulate(comb)) # Get aaa_xyz. aaa_xyz = [[x, y, z] for z in range(64) for y in range(z) for x in range(y)] From 57536b1a0787cecf0a725ac50e9ce98e65340f11 Mon Sep 17 00:00:00 2001 From: "Robert Nurnberg @ elitebook" Date: Mon, 20 Jan 2025 08:49:28 +0100 Subject: [PATCH 232/250] fix typo in comment --- chess/syzygy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/syzygy.py b/chess/syzygy.py index 5ead9922c..c61890550 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -1850,7 +1850,7 @@ def probe_dtz(self, board: chess.Board) -> int: +-----+------------------+--------------------------------------------+ 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 + losing zeroing move in n + 1 plies and a return value +n can mean a winning zeroing move in n + 1 plies. This implies some primary tablebase lines may waste up to 1 ply. Rounding is never used for endgame phases where it would change the From 636e95fbf292f322fc4ab31b8c4add51f7534362 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 23 Feb 2025 21:05:39 +0100 Subject: [PATCH 233/250] Revert simplifications of chess.gaviota from #1130 The resulting code is not equivalent, that is, when the full tablebase is available ./test.py GaviotaTestCase fails with ERROR: test_dm_4 (__main__.GaviotaTestCase.test_dm_4) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/niklas/Projekte/python-chess/./test.py", line 35, in _wrapper return f(self) File "/home/niklas/Projekte/python-chess/./test.py", line 4305, in test_dm_4 dtm = self.tablebase.probe_dtm(board) File "/home/niklas/Projekte/python-chess/chess/gaviota.py", line 1393, in probe_dtm dtm = self.egtb_get_dtm(req) File "/home/niklas/Projekte/python-chess/chess/gaviota.py", line 1518, in egtb_get_dtm dtm = self._tb_probe(req) File "/home/niklas/Projekte/python-chess/chess/gaviota.py", line 1621, in _tb_probe buffer_zipped = stream.read(z) ValueError: read length must be non-negative or -1 --- chess/gaviota.py | 553 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 374 insertions(+), 179 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 0bbe41b81..39173b593 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -4,7 +4,6 @@ import ctypes.util import dataclasses import fnmatch -import itertools import logging import lzma import os @@ -12,11 +11,11 @@ import struct import typing +import chess + from types import TracebackType from typing import BinaryIO, Callable, Dict, List, Optional, Tuple, Type, Union -import chess - LOGGER = logging.getLogger(__name__) @@ -110,19 +109,30 @@ def idx_is_empty(x: int) -> int: def flip_type(x: chess.Square, y: chess.Square) -> int: ret = 0 - file_x, rank_x = chess.square_file(x), chess.square_rank(x) - file_y, rank_y = chess.square_file(y), chess.square_rank(y) - if file_x > 3: - x, y = flip_we(x), flip_we(y) + if chess.square_file(x) > 3: + x = flip_we(x) + y = flip_we(y) ret |= 1 - if rank_x > 3: - x, y = flip_ns(x), flip_ns(y) + if chess.square_rank(x) > 3: + x = flip_ns(x) + y = flip_ns(y) ret |= 2 - if (rank_x, file_x) > (rank_y, file_y): - x, y = flip_nw_se(x), flip_nw_se(y) + rowx = chess.square_rank(x) + colx = chess.square_file(x) + + if rowx > colx: + x = flip_nw_se(x) + y = flip_nw_se(y) + ret |= 4 + + rowy = chess.square_rank(y) + coly = chess.square_file(y) + if rowx == colx and rowy > coly: + x = flip_nw_se(x) + y = flip_nw_se(y) ret |= 4 return ret @@ -135,6 +145,7 @@ def init_flipt() -> List[List[int]]: def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: MAX_I = MAX_J = 48 + idx = 0 pp48_idx = [[-1] * MAX_J for _ in range(MAX_I)] pp48_sq_x = [NOSQUARE] * MAX_PP48_INDEX pp48_sq_y = [NOSQUARE] * MAX_PP48_INDEX @@ -146,8 +157,10 @@ def init_pp48_idx() -> Tuple[List[List[int]], List[int], List[int]]: j = flip_we(flip_ns(b)) - 8 if idx_is_empty(pp48_idx[i][j]): - pp48_idx[i][j] = pp48_idx[j][i] = idx - pp48_sq_x[idx], pp48_sq_y[idx] = i, j + pp48_idx[i][j] = idx + pp48_idx[j][i] = idx + pp48_sq_x[idx] = i + pp48_sq_y[idx] = j idx += 1 return pp48_idx, pp48_sq_x, pp48_sq_y @@ -166,15 +179,26 @@ def init_ppp48_idx() -> Tuple[List[List[List[int]]], List[int], List[int], List[ for x in range(48): for y in range(x + 1, 48): for z in range(y + 1, 48): - if not (in_queenside(ITOSQ[y]) and in_queenside(ITOSQ[z])): + a = ITOSQ[x] + b = ITOSQ[y] + c = ITOSQ[z] + if not in_queenside(b) or not in_queenside(c): continue - i, j, k = ITOSQ[x] - 8, ITOSQ[y] - 8, ITOSQ[z] - 8 + i = a - 8 + j = b - 8 + k = c - 8 if idx_is_empty(ppp48_idx[i][j][k]): - for ii, jj, kk in itertools.permutations((i, j, k)): - ppp48_idx[ii][jj][kk] = idx - ppp48_sq_x[idx], ppp48_sq_y[idx], ppp48_sq_z[idx] = i, j, k + ppp48_idx[i][j][k] = idx + ppp48_idx[i][k][j] = idx + ppp48_idx[j][i][k] = idx + ppp48_idx[j][k][i] = idx + ppp48_idx[k][i][j] = idx + ppp48_idx[k][j][i] = idx + ppp48_sq_x[idx] = i + ppp48_sq_y[idx] = j + ppp48_sq_z[idx] = k idx += 1 return ppp48_idx, ppp48_sq_x, ppp48_sq_y, ppp48_sq_z @@ -192,7 +216,8 @@ def init_aaidx() -> Tuple[List[int], List[List[int]]]: if idx_is_empty(aaidx[x][y]): # Still empty. - aaidx[x][y] = aaidx[y][x] = idx + aaidx[x][y] = idx + aaidx[y][x] = idx aabase[idx] = x idx += 1 @@ -204,10 +229,24 @@ def init_aaidx() -> Tuple[List[int], List[List[int]]]: def init_aaa() -> Tuple[List[int], List[List[int]]]: # Get aaa_base. comb = [a * (a - 1) // 2 for a in range(64)] - aaa_base = list(itertools.accumulate(comb)) + + accum = 0 + aaa_base = [0] * 64 + for a in range(64 - 1): + accum += comb[a] + aaa_base[a + 1] = accum # Get aaa_xyz. - aaa_xyz = [[x, y, z] for z in range(64) for y in range(z) for x in range(y)] + aaa_xyz = [[-1] * 3 for _ in range(MAX_AAAINDEX)] + + idx = 0 + for z in range(64): + for y in range(z): + for x in range(y): + aaa_xyz[idx][0] = x + aaa_xyz[idx][1] = y + aaa_xyz[idx][2] = z + idx += 1 return aaa_base, aaa_xyz @@ -312,33 +351,34 @@ def init_ppidx() -> Tuple[List[List[int]], List[int], List[int]]: def norm_kkindex(x: chess.Square, y: chess.Square) -> Tuple[int, int]: - file_x, rank_x = chess.square_file(x), chess.square_rank(x) - - if file_x > 3: - x, y = flip_we(x), flip_we(y) + if chess.square_file(x) > 3: + x = flip_we(x) + y = flip_we(y) - if rank_x > 3: - x, y = flip_ns(x), flip_ns(y) + if chess.square_rank(x) > 3: + x = flip_ns(x) + y = flip_ns(y) rowx = chess.square_rank(x) colx = chess.square_file(x) if rowx > colx: - x, y = flip_nw_se(x), flip_nw_se(y) + x = flip_nw_se(x) + y = flip_nw_se(y) rowy = chess.square_rank(y) coly = chess.square_file(y) if rowx == colx and rowy > coly: - x, y = flip_nw_se(x), flip_nw_se(y) + x = flip_nw_se(x) + y = flip_nw_se(y) return x, y - def init_kkidx() -> Tuple[List[List[int]], List[int], List[int]]: kkidx = [[-1] * 64 for _ in range(64)] - bksq, wksq = [-1] * MAX_KKINDEX, [-1] * MAX_KKINDEX - + bksq = [-1] * MAX_KKINDEX + wksq = [-1] * MAX_KKINDEX idx = 0 for x in range(64): for y in range(64): @@ -348,8 +388,10 @@ def init_kkidx() -> Tuple[List[List[int]], List[int], List[int]]: i, j = norm_kkindex(x, y) if idx_is_empty(kkidx[i][j]): - kkidx[i][j] = kkidx[x][y] = idx - bksq[idx], wksq[idx] = i, j + kkidx[i][j] = idx + kkidx[x][y] = idx + bksq[idx] = i + wksq[idx] = j idx += 1 return kkidx, wksq, bksq @@ -362,12 +404,20 @@ def kxk_pctoindex(c: Request) -> int: ft = flip_type(c.black_piece_squares[0], c.white_piece_squares[0]) - ws, bs = c.white_piece_squares, c.black_piece_squares + ws = c.white_piece_squares + bs = c.black_piece_squares + + if (ft & 1) != 0: + ws = [flip_we(b) for b in ws] + bs = [flip_we(b) for b in bs] + + if (ft & 2) != 0: + ws = [flip_ns(b) for b in ws] + bs = [flip_ns(b) for b in bs] - for f, flip in [(1, flip_we), (2, flip_ns), (4, flip_nw_se)]: - if ft & f: - ws = [flip(b) for b in ws] - bs = [flip(b) for b in bs] + if (ft & 4) != 0: + ws = [flip_nw_se(b) for b in ws] + bs = [flip_nw_se(b) for b in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] @@ -376,14 +426,6 @@ def kxk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] - -def flip_we_col(*pieces: int) -> tuple[int, ...]: - if (pieces[0] & 7) > 3: - # Column is more than 3, i.e., e, f, g or h. - pieces = tuple(flip_we(piece) for piece in pieces) - return pieces - - def kapkb_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 * 64 BLOCK_B = 64 * 64 * 64 @@ -396,17 +438,24 @@ def kapkb_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] ba = c.black_piece_squares[1] - if not chess.A2 <= pawn < chess.A8: + if not (chess.A2 <= pawn < chess.A8): return NOINDEX - pawn, wk, bk, wa, ba = flip_we_col(pawn, wk, bk, wa, ba) + if (pawn & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) + ba = flip_we(ba) - # flip_ns, down one row - pslice = ((pawn ^ 56) - 8 + (pawn & 3)) >> 1 + sq = pawn + sq ^= 56 # flip_ns + sq -= 8 # Down one row + pslice = (sq + (sq & 3)) >> 1 return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa * BLOCK_D + ba - def kabpk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 * 64 BLOCK_B = 64 * 64 * 64 @@ -419,13 +468,18 @@ def kabpk_pctoindex(c: Request) -> int: pawn = c.white_piece_squares[3] bk = c.black_piece_squares[0] - pawn, wk, bk, wa, wb = flip_we_col(pawn, wk, bk, wa, wb) + if (pawn & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) + wb = flip_we(wb) pslice = wsq_to_pidx24(pawn) return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa * BLOCK_D + wb - def kabkp_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 * 64 BLOCK_B = 64 * 64 * 64 @@ -438,17 +492,23 @@ def kabkp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] wb = c.white_piece_squares[2] - if not chess.A2 <= pawn < chess.A8: + if not (chess.A2 <= pawn < chess.A8): return NOINDEX - pawn, wk, bk, wa, wb = flip_we_col(pawn, wk, bk, wa, wb) + if (pawn & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) + wb = flip_we(wb) - # Down one row - pslice = ((pawn - 8) + (pawn & 3)) >> 1 + sq = pawn + sq -= 8 # Down one row + pslice = (sq + (sq & 3)) >> 1 return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa * BLOCK_D + wb - def kaapk_pctoindex(c: Request) -> int: BLOCK_C = MAX_AAINDEX BLOCK_B = 64 * BLOCK_C @@ -460,7 +520,13 @@ def kaapk_pctoindex(c: Request) -> int: pawn = c.white_piece_squares[3] bk = c.black_piece_squares[0] - pawn, wk, bk, wa, wa2 = flip_we_col(pawn, wk, bk, wa, wa2) + if (pawn & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) + wa2 = flip_we(wa2) pslice = wsq_to_pidx24(pawn) @@ -471,7 +537,6 @@ def kaapk_pctoindex(c: Request) -> int: return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + aa_combo - def kaakp_pctoindex(c: Request) -> int: BLOCK_C = MAX_AAINDEX BLOCK_B = 64 * BLOCK_C @@ -483,7 +548,13 @@ def kaakp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] pawn = c.black_piece_squares[1] - pawn, wk, bk, wa, wa2 = flip_we_col(pawn, wk, bk, wa, wa2) + if (pawn & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) + wa2 = flip_we(wa2) pawn = flip_ns(pawn) pslice = wsq_to_pidx24(pawn) @@ -495,7 +566,6 @@ def kaakp_pctoindex(c: Request) -> int: return pslice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + aa_combo - def kapkp_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 BLOCK_B = 64 * 64 @@ -503,20 +573,30 @@ def kapkp_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] wa = c.white_piece_squares[1] - anchor = c.white_piece_squares[2] + pawn_a = c.white_piece_squares[2] bk = c.black_piece_squares[0] - loosen = c.black_piece_squares[1] + pawn_b = c.black_piece_squares[1] + + anchor = pawn_a + loosen = pawn_b - anchor, loosen, wk, bk, wa = flip_we_col(anchor, loosen, wk, bk, wa) + if (anchor & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + anchor = flip_we(anchor) + loosen = flip_we(loosen) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) - pp_slice = wsq_to_pidx24(anchor) * 48 + loosen - 8 + m = wsq_to_pidx24(anchor) + n = loosen - 8 + pp_slice = m * 48 + n if idx_is_empty(pp_slice): return NOINDEX return pp_slice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa - def kappk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 BLOCK_B = 64 * 64 @@ -530,7 +610,13 @@ def kappk_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - anchor, loosen, wk, bk, wa = flip_we_col(anchor, loosen, wk, bk, wa) + if (anchor & 7) > 3: + # Column is more than 3, i.e., e, f, g or h. + anchor = flip_we(anchor) + loosen = flip_we(loosen) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) @@ -542,7 +628,6 @@ def kappk_pctoindex(c: Request) -> int: return pp_slice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + wa - def kppka_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 * 64 BLOCK_B = 64 * 64 @@ -556,7 +641,12 @@ def kppka_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - anchor, loosen, wk, bk, ba = flip_we_col(anchor, loosen, wk, bk, ba) + if (anchor & 7) > 3: + anchor = flip_we(anchor) + loosen = flip_we(loosen) + wk = flip_we(wk) + bk = flip_we(bk) + ba = flip_we(ba) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) @@ -568,7 +658,6 @@ def kppka_pctoindex(c: Request) -> int: return pp_slice * BLOCK_A + wk * BLOCK_B + bk * BLOCK_C + ba - def kabck_pctoindex(c: Request) -> int: N_WHITE = 4 N_BLACK = 1 @@ -600,7 +689,6 @@ def kabck_pctoindex(c: Request) -> int: return ki * BLOCK_A + ws[1] * BLOCK_B + ws[2] * BLOCK_C + ws[3] - def kabbk_pctoindex(c: Request) -> int: N_WHITE = 4 N_BLACK = 1 @@ -632,7 +720,6 @@ def kabbk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai * BLOCK_Bx + ws[1] - def kaabk_pctoindex(c: Request) -> int: N_WHITE = 4 N_BLACK = 1 @@ -664,23 +751,45 @@ def kaabk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai * BLOCK_Bx + ws[3] - def aaa_getsubi(x: int, y: int, z: int) -> int: - return x + (y - 1) * y // 2 + AAA_BASE[z] - + bse = AAA_BASE[z] + calc_idx = x + (y - 1) * y // 2 + bse + return calc_idx def kaaak_pctoindex(c: Request) -> int: + N_WHITE = 4 + N_BLACK = 1 BLOCK_Ax = MAX_AAAINDEX - ws = c.white_piece_squares[:4] - bs = c.black_piece_squares[:1] + + ws = c.white_piece_squares[:N_WHITE] + bs = c.black_piece_squares[:N_BLACK] + ft = FLIPT[c.black_piece_squares[0]][c.white_piece_squares[0]] - for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: - if ft & flag: - ws = [flip(i) for i in ws] - bs = [flip(i) for i in bs] + if (ft & WE_FLAG) != 0: + ws = [flip_we(i) for i in ws] + bs = [flip_we(i) for i in bs] + + if (ft & NS_FLAG) != 0: + ws = [flip_ns(i) for i in ws] + bs = [flip_ns(i) for i in bs] - ws[1:4] = sorted(ws[1:4]) + if (ft & NW_SE_FLAG) != 0: + ws = [flip_nw_se(i) for i in ws] + bs = [flip_nw_se(i) for i in bs] + + if ws[2] < ws[1]: + tmp = ws[1] + ws[1] = ws[2] + ws[2] = tmp + if ws[3] < ws[2]: + tmp = ws[2] + ws[2] = ws[3] + ws[3] = tmp + if ws[2] < ws[1]: + tmp = ws[1] + ws[1] = ws[2] + ws[2] = tmp ki = KKIDX[bs[0]][ws[0]] @@ -694,7 +803,6 @@ def kaaak_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai - def kppkp_pctoindex(c: Request) -> int: BLOCK_Ax = MAX_PP48_INDEX * 64 * 64 BLOCK_Bx = 64 * 64 @@ -706,7 +814,12 @@ def kppkp_pctoindex(c: Request) -> int: bk = c.black_piece_squares[0] pawn_c = c.black_piece_squares[1] - pawn_c, wk, pawn_a, pawn_b, bk = flip_we_col(pawn_c, wk, pawn_a, pawn_b, bk) + if (pawn_c & 7) > 3: + wk = flip_we(wk) + pawn_a = flip_we(pawn_a) + pawn_b = flip_we(pawn_b) + bk = flip_we(bk) + pawn_c = flip_we(pawn_c) i = flip_we(flip_ns(pawn_a)) - 8 j = flip_we(flip_ns(pawn_b)) - 8 @@ -721,19 +834,28 @@ def kppkp_pctoindex(c: Request) -> int: return k * BLOCK_Ax + pp48_slice * BLOCK_Bx + wk * BLOCK_Cx + bk - def kaakb_pctoindex(c: Request) -> int: + N_WHITE = 3 + N_BLACK = 2 BLOCK_Bx = 64 BLOCK_Ax = BLOCK_Bx * MAX_AAINDEX - ws = c.white_piece_squares[:3] - bs = c.black_piece_squares[:2] ft = FLIPT[c.black_piece_squares[0]][c.white_piece_squares[0]] - for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: - if ft & flag: - ws = [flip(i) for i in ws] - bs = [flip(i) for i in bs] + ws = c.white_piece_squares[:N_WHITE] + bs = c.black_piece_squares[:N_BLACK] + + if (ft & WE_FLAG) != 0: + ws = [flip_we(i) for i in ws] + bs = [flip_we(i) for i in bs] + + if (ft & NS_FLAG) != 0: + ws = [flip_ns(i) for i in ws] + bs = [flip_ns(i) for i in bs] + + if (ft & NW_SE_FLAG) != 0: + ws = [flip_nw_se(i) for i in ws] + bs = [flip_nw_se(i) for i in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] ai = AAIDX[ws[1]][ws[2]] @@ -743,7 +865,6 @@ def kaakb_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai * BLOCK_Bx + bs[1] - def kabkc_pctoindex(c: Request) -> int: N_WHITE = 3 N_BLACK = 2 @@ -757,10 +878,17 @@ def kabkc_pctoindex(c: Request) -> int: ws = c.white_piece_squares[:N_WHITE] bs = c.black_piece_squares[:N_BLACK] - for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: - if ft & flag: - ws = [flip(i) for i in ws] - bs = [flip(i) for i in bs] + if (ft & WE_FLAG) != 0: + ws = [flip_we(i) for i in ws] + bs = [flip_we(i) for i in bs] + + if (ft & NS_FLAG) != 0: + ws = [flip_ns(i) for i in ws] + bs = [flip_ns(i) for i in bs] + + if (ft & NW_SE_FLAG) != 0: + ws = [flip_nw_se(i) for i in ws] + bs = [flip_nw_se(i) for i in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX [black king] [white king] @@ -769,17 +897,23 @@ def kabkc_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] * BLOCK_Bx + ws[2] * BLOCK_Cx + bs[1] - def kpkp_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - anchor = c.white_piece_squares[1] - loosen = c.black_piece_squares[1] + pawn_a = c.white_piece_squares[1] + pawn_b = c.black_piece_squares[1] - anchor, loosen, wk, bk = flip_we_col(anchor, loosen, wk, bk) + anchor = pawn_a + loosen = pawn_b + + if (anchor & 7) > 3: + anchor = flip_we(anchor) + loosen = flip_we(loosen) + wk = flip_we(wk) + bk = flip_we(bk) m = wsq_to_pidx24(anchor) n = loosen - 8 @@ -791,7 +925,6 @@ def kpkp_pctoindex(c: Request) -> int: return pp_slice * BLOCK_Ax + wk * BLOCK_Bx + bk - def kppk_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 @@ -802,7 +935,11 @@ def kppk_pctoindex(c: Request) -> int: anchor, loosen = pp_putanchorfirst(pawn_a, pawn_b) - anchor, loosen, wk, bk = flip_we_col(anchor, loosen, wk, bk) + if (anchor & 7) > 3: + anchor = flip_we(anchor) + loosen = flip_we(loosen) + wk = flip_we(wk) + bk = flip_we(bk) i = wsq_to_pidx24(anchor) j = wsq_to_pidx48(loosen) @@ -814,7 +951,6 @@ def kppk_pctoindex(c: Request) -> int: return pp_slice * BLOCK_Ax + wk * BLOCK_Bx + bk - def kapk_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 * 64 BLOCK_Bx = 64 * 64 @@ -825,17 +961,22 @@ def kapk_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - if not chess.A2 <= pawn < chess.A8: + if not (chess.A2 <= pawn < chess.A8): return NOINDEX - pawn, wk, bk, wa = flip_we_col(pawn, wk, bk, wa) + if (pawn & 7) > 3: + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) - sq = pawn ^ 56 - 8 # flip_ns and down one row + sq = pawn + sq ^= 56 # flip_ns + sq -= 8 # Down one row pslice = ((sq + (sq & 3)) >> 1) return pslice * BLOCK_Ax + wk * BLOCK_Bx + bk * BLOCK_Cx + wa - def kabk_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 @@ -845,10 +986,17 @@ def kabk_pctoindex(c: Request) -> int: ws = c.white_piece_squares bs = c.black_piece_squares - for flag, flip in [(1, flip_we), (2, flip_ns), (4, flip_nw_se)]: - if ft & flag: - ws = [flip(b) for b in ws] - bs = [flip(b) for b in bs] + if (ft & 1) != 0: + ws = [flip_we(b) for b in ws] + bs = [flip_we(b) for b in bs] + + if (ft & 2) != 0: + ws = [flip_ns(b) for b in ws] + bs = [flip_ns(b) for b in bs] + + if (ft & 4) != 0: + ws = [flip_nw_se(b) for b in ws] + bs = [flip_nw_se(b) for b in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] @@ -857,7 +1005,6 @@ def kabk_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] * BLOCK_Bx + ws[2] - def kakp_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 * 64 BLOCK_Bx = 64 * 64 @@ -868,29 +1015,42 @@ def kakp_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - if not chess.A2 <= pawn < chess.A8: + if not (chess.A2 <= pawn < chess.A8): return NOINDEX - pawn, wk, bk, wa = flip_we_col(pawn, wk, bk, wa) + if (pawn & 7) > 3: + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) + wa = flip_we(wa) - # Down one row - pslice = ((pawn - 8) + ((pawn - 8) & 3)) >> 1 + sq = pawn + sq -= 8 # Down one row + pslice = (sq + (sq & 3)) >> 1 return pslice * BLOCK_Ax + wk * BLOCK_Bx + bk * BLOCK_Cx + wa - def kaak_pctoindex(c: Request) -> int: + N_WHITE = 3 + N_BLACK = 1 BLOCK_Ax = MAX_AAINDEX ft = FLIPT[c.black_piece_squares[0]][c.white_piece_squares[0]] - ws = c.white_piece_squares[:3] - bs = c.black_piece_squares[:1] + ws = c.white_piece_squares[:N_WHITE] + bs = c.black_piece_squares[:N_BLACK] + + if (ft & WE_FLAG) != 0: + ws = [flip_we(i) for i in ws] + bs = [flip_we(i) for i in bs] - for flag, flip in [(WE_FLAG, flip_we), (NS_FLAG, flip_ns), (NW_SE_FLAG, flip_nw_se)]: - if ft & flag: - ws = [flip(i) for i in ws] - bs = [flip(i) for i in bs] + if (ft & NS_FLAG) != 0: + ws = [flip_ns(i) for i in ws] + bs = [flip_ns(i) for i in bs] + + if (ft & NW_SE_FLAG) != 0: + ws = [flip_nw_se(i) for i in ws] + bs = [flip_nw_se(i) for i in bs] ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] ai = AAIDX[ws[1]][ws[2]] @@ -900,7 +1060,6 @@ def kaak_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ai - def kakb_pctoindex(c: Request) -> int: BLOCK_Ax = 64 * 64 BLOCK_Bx = 64 @@ -910,9 +1069,23 @@ def kakb_pctoindex(c: Request) -> int: ws = c.white_piece_squares[:] bs = c.black_piece_squares[:] - for bit, flip in [(1, flip_we), (2, flip_ns), (4, flip_nw_se)]: - if ft & bit: - ws[0], ws[1], bs[0], bs[1] = flip(ws[0]), flip(ws[1]), flip(bs[0]), flip(bs[1]) + if (ft & 1) != 0: + ws[0] = flip_we(ws[0]) + ws[1] = flip_we(ws[1]) + bs[0] = flip_we(bs[0]) + bs[1] = flip_we(bs[1]) + + if (ft & 2) != 0: + ws[0] = flip_ns(ws[0]) + ws[1] = flip_ns(ws[1]) + bs[0] = flip_ns(bs[0]) + bs[1] = flip_ns(bs[1]) + + if (ft & 4) != 0: + ws[0] = flip_nw_se(ws[0]) + ws[1] = flip_nw_se(ws[1]) + bs[0] = flip_nw_se(bs[0]) + bs[1] = flip_nw_se(bs[1]) ki = KKIDX[bs[0]][ws[0]] # KKIDX[black king][white king] @@ -921,7 +1094,6 @@ def kakb_pctoindex(c: Request) -> int: return ki * BLOCK_Ax + ws[1] * BLOCK_Bx + bs[1] - def kpk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 BLOCK_B = 64 @@ -930,16 +1102,21 @@ def kpk_pctoindex(c: Request) -> int: wk = c.white_piece_squares[0] bk = c.black_piece_squares[0] - if not chess.A2 <= pawn < chess.A8: + if not (chess.A2 <= pawn < chess.A8): return NOINDEX - pawn, wk, bk = flip_we_col(pawn, wk, bk) + if (pawn & 7) > 3: + pawn = flip_we(pawn) + wk = flip_we(wk) + bk = flip_we(bk) - sq = (pawn ^ 56) - 8 # flip_ns, down one row + sq = pawn + sq ^= 56 # flip_ns + sq -= 8 # Down one row pslice = ((sq + (sq & 3)) >> 1) - return pslice * BLOCK_A + wk * BLOCK_B + bk - + res = pslice * BLOCK_A + wk * BLOCK_B + bk + return res def kpppk_pctoindex(c: Request) -> int: BLOCK_A = 64 * 64 @@ -949,16 +1126,26 @@ def kpppk_pctoindex(c: Request) -> int: pawn_a = c.white_piece_squares[1] pawn_b = c.white_piece_squares[2] pawn_c = c.white_piece_squares[3] + bk = c.black_piece_squares[0] - i, j, k = [x - 8 for x in (pawn_a, pawn_b, pawn_c)] + i = pawn_a - 8 + j = pawn_b - 8 + k = pawn_c - 8 + ppp48_slice = PPP48_IDX[i][j][k] if idx_is_empty(ppp48_slice): - wk, pawn_a, pawn_b, pawn_c, bk = [flip_we(x) for x in (wk, pawn_a, pawn_b, pawn_c, bk)] + wk = flip_we(wk) + pawn_a = flip_we(pawn_a) + pawn_b = flip_we(pawn_b) + pawn_c = flip_we(pawn_c) + bk = flip_we(bk) + + i = pawn_a - 8 + j = pawn_b - 8 + k = pawn_c - 8 - # removing this doesn't impact the tests? - i, j, k = [x - 8 for x in (pawn_a, pawn_b, pawn_c)] ppp48_slice = PPP48_IDX[i][j][k] if idx_is_empty(ppp48_slice): @@ -1143,15 +1330,13 @@ def __init__(self, maxindex: int, slice_n: int, pctoi: Callable[[Request], int]) def sortlists(ws: List[int], wp: List[int]) -> Tuple[List[int], List[int]]: - z = sorted(zip(wp, ws), reverse=True) + z = sorted(zip(wp, ws), key=lambda x: x[0], reverse=True) wp2, ws2 = zip(*z) return list(ws2), list(wp2) - def egtb_block_unpack(side: int, n: int, bp: bytes) -> List[int]: return [dtm_unpack(side, i) for i in bp[:n]] - def split_index(i: int) -> Tuple[int, int]: return divmod(i, ENTRIES_PER_BLOCK) @@ -1175,23 +1360,19 @@ def removepiece(ys: List[int], yp: List[int], j: int) -> None: del ys[j] del yp[j] - def opp(side: int) -> int: return 1 if side == 0 else 0 - def adjust_up(dist: int) -> int: - if (dist & INFOMASK) in [iWMATE, iWMATEt, iBMATE, iBMATEt]: - return dist + (1 << PLYSHIFT) - return dist + udist = dist + sw = udist & INFOMASK + if sw in [iWMATE, iWMATEt, iBMATE, iBMATEt]: + udist += (1 << PLYSHIFT) -def bestx(side: int, a: int, b: int) -> int: - if a == iFORBID: - return b - if b == iFORBID: - return a + return udist +def bestx(side: int, a: int, b: int) -> int: # 0 = selectfirst # 1 = selectlowest # 2 = selecthighest @@ -1204,25 +1385,33 @@ def bestx(side: int, a: int, b: int) -> int: [3, 3, 3, 0], # forbid ] + xorkey = [0, 3] + + if a == iFORBID: + return b + if b == iFORBID: + return a + retu = [a, a, b, b] if b < a: - retu[1:2] = [b, a] + retu[1] = b + retu[2] = a - key = comparison[a & 3][b & 3] ^ [0, 3][side] # ^ xorkey + key = comparison[a & 3][b & 3] ^ xorkey[side] return retu[key] - def unpackdist(d: int) -> Tuple[int, int]: return d >> PLYSHIFT, d & INFOMASK - def dtm_unpack(stm: int, packed: int) -> int: - if packed in [iDRAW, iFORBID]: - return packed + p = packed + + if p in [iDRAW, iFORBID]: + return p - info = packed & 3 - store = packed >> 2 + info = p & 3 + store = p >> 2 if stm == 0: if info == iWMATE: @@ -1398,23 +1587,28 @@ def probe_dtm(self, board: chess.Board) -> int: if req.realside == 1: if req.is_reversed: return ply - return -ply - if req.is_reversed: - return -ply - return ply - - if res == iBMATE: + else: + return -ply + else: + if req.is_reversed: + return -ply + else: + return ply + elif res == iBMATE: # Black mates in the stored position. if req.realside == 0: if req.is_reversed: return ply - return -ply - if req.is_reversed: - return -ply - return ply - - # Draw. - return 0 + else: + return -ply + else: + if req.is_reversed: + return -ply + else: + return ply + else: + # Draw. + return 0 def get_dtm(self, board: chess.Board, default: Optional[int] = None) -> Optional[int]: try: @@ -1450,12 +1644,12 @@ def probe_wdl(self, board: chess.Board) -> int: if dtm == 0: if board.is_checkmate(): return -1 - return 0 - - if dtm > 0: + else: + return 0 + elif dtm > 0: return 1 - - return -1 + else: + return -1 def get_wdl(self, board: chess.Board, default: Optional[int] = None) -> Optional[int]: try: @@ -1601,7 +1795,8 @@ def egtb_block_getsize(self, req: Request, idx: int) -> int: if (offset + blocksz) > maxindex: return maxindex - offset # Last block size - return blocksz # Size of a normal block + else: + return blocksz # Size of a normal block def _tb_probe(self, req: Request) -> int: stream = self._setup_tablebase(req) From dd4d9c1285d70f1aaffa276244101d9373053c1d Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sun, 23 Feb 2025 22:55:23 +0100 Subject: [PATCH 234/250] Fix ep resolution in chess.gaviota.PythonTablebase (fixes #1132) --- chess/gaviota.py | 142 +++++++---------------------------------------- test.py | 5 ++ 2 files changed, 26 insertions(+), 121 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 39173b593..83fb7bb64 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -1356,51 +1356,9 @@ def split_index(i: int) -> Tuple[int, int]: iBMATEt = tb_BMATE | 4 -def removepiece(ys: List[int], yp: List[int], j: int) -> None: - del ys[j] - del yp[j] - def opp(side: int) -> int: return 1 if side == 0 else 0 -def adjust_up(dist: int) -> int: - udist = dist - sw = udist & INFOMASK - - if sw in [iWMATE, iWMATEt, iBMATE, iBMATEt]: - udist += (1 << PLYSHIFT) - - return udist - -def bestx(side: int, a: int, b: int) -> int: - # 0 = selectfirst - # 1 = selectlowest - # 2 = selecthighest - # 3 = selectsecond - comparison = [ - # draw, wmate, bmate, forbid - [0, 3, 0, 0], # draw - [0, 1, 0, 0], # wmate - [3, 3, 2, 0], # bmate - [3, 3, 3, 0], # forbid - ] - - xorkey = [0, 3] - - if a == iFORBID: - return b - if b == iFORBID: - return a - - retu = [a, a, b, b] - - if b < a: - retu[1] = b - retu[2] = a - - key = comparison[a & 3][b & 3] ^ xorkey[side] - return retu[key] - def unpackdist(d: int) -> Tuple[int, int]: return d >> PLYSHIFT, d & INFOMASK @@ -1492,12 +1450,11 @@ class Request: black_piece_types: List[int] is_reversed: bool - def __init__(self, white_squares: List[int], white_types: List[chess.PieceType], black_squares: List[int], black_types: List[chess.PieceType], side: int, epsq: int): + def __init__(self, white_squares: List[int], white_types: List[chess.PieceType], black_squares: List[int], black_types: List[chess.PieceType], side: int): self.white_squares, self.white_types = sortlists(white_squares, white_types) self.black_squares, self.black_types = sortlists(black_squares, black_types) self.realside = side self.side = side - self.epsq = epsq @dataclasses.dataclass @@ -1569,17 +1526,34 @@ def probe_dtm(self, board: chess.Board) -> int: if board.occupied == board.kings: return 0 + # Resolve en passant. + dtm = self._probe_dtm_no_ep(board) + for move in board.generate_legal_ep(): + try: + board.push(move) + + child_dtm = -self._probe_dtm_no_ep(board) + if child_dtm > 0: + child_dtm += 1 + elif child_dtm < 0: + child_dtm -= 1 + + dtm = min(dtm, child_dtm) if dtm * child_dtm > 0 else max(dtm, child_dtm) + finally: + board.pop() + return dtm + + def _probe_dtm_no_ep(self, board: chess.Board) -> int: # Prepare the tablebase request. white_squares = list(chess.SquareSet(board.occupied_co[chess.WHITE])) white_types = [typing.cast(chess.PieceType, board.piece_type_at(sq)) for sq in white_squares] black_squares = list(chess.SquareSet(board.occupied_co[chess.BLACK])) black_types = [typing.cast(chess.PieceType, board.piece_type_at(sq)) for sq in black_squares] side = 0 if (board.turn == chess.WHITE) else 1 - epsq = board.ep_square if board.ep_square else NOSQUARE - req = Request(white_squares, white_types, black_squares, black_types, side, epsq) + req = Request(white_squares, white_types, black_squares, black_types, side) # Probe. - dtm = self.egtb_get_dtm(req) + dtm = self._tb_probe(req) ply, res = unpackdist(dtm) if res == iWMATE: @@ -1675,10 +1649,7 @@ def _setup_tablebase(self, req: Request) -> BinaryIO: req.white_piece_types = req.black_types req.black_piece_squares = [flip_ns(s) for s in req.white_squares] req.black_piece_types = req.white_types - req.side = opp(req.side) - if req.epsq != NOSQUARE: - req.epsq = flip_ns(req.epsq) else: raise MissingTableError(f"no gaviota table available for: {white_letters.upper()}v{black_letters.upper()}") @@ -1708,77 +1679,6 @@ def close(self) -> None: _, stream = self.streams.popitem() stream.close() - def egtb_get_dtm(self, req: Request) -> int: - dtm = self._tb_probe(req) - - if req.epsq != NOSQUARE: - capturer_a = 0 - capturer_b = 0 - xed = 0 - - # Flip for move generation. - if req.side == 0: - xs = list(req.white_piece_squares) - xp = list(req.white_piece_types) - ys = list(req.black_piece_squares) - yp = list(req.black_piece_types) - else: - xs = list(req.black_piece_squares) - xp = list(req.black_piece_types) - ys = list(req.white_piece_squares) - yp = list(req.white_piece_types) - - # Captured pawn trick: from ep square to captured. - xed = req.epsq ^ (1 << 3) - - # Find captured index (j). - try: - j = ys.index(xed) - except ValueError: - j = -1 - - # Try first possible ep capture. - if 0 == (0x88 & (map88(xed) + 1)): - capturer_a = xed + 1 - - # Try second possible ep capture. - if 0 == (0x88 & (map88(xed) - 1)): - capturer_b = xed - 1 - - if (j > -1) and (ys[j] == xed): - # Find capturers (i). - for i in range(len(xs)): - if xp[i] == chess.PAWN and (xs[i] == capturer_a or xs[i] == capturer_b): - epscore = iFORBID - - # Copy position. - xs_after = xs[:] - ys_after = ys[:] - xp_after = xp[:] - yp_after = yp[:] - - # Execute capture. - xs_after[i] = req.epsq - removepiece(ys_after, yp_after, j) - - # Flip back. - if req.side == 1: - xs_after, ys_after = ys_after, xs_after - xp_after, yp_after = yp_after, xp_after - - # Make subrequest. - subreq = Request(xs_after, xp_after, ys_after, yp_after, opp(req.side), NOSQUARE) - try: - epscore = self._tb_probe(subreq) - epscore = adjust_up(epscore) - - # Choose to ep or not. - dtm = bestx(req.side, epscore, dtm) - except IndexError: - break - - return dtm - def egtb_block_getnumber(self, req: Request, idx: int) -> int: maxindex = EGKEY[req.egkey].maxindex diff --git a/test.py b/test.py index 6db84d254..7a3a3cdef 100755 --- a/test.py +++ b/test.py @@ -4348,6 +4348,11 @@ def test_two_ep(self): board = chess.Board("K7/8/8/6k1/5pPp/8/8/8 b - g3 0 61") self.assertEqual(self.tablebase.probe_dtm(board), 17) + @catchAndSkip(chess.gaviota.MissingTableError, "need KPvKP.gtb.cp4") + def test_ep_is_best(self): + board = chess.Board("8/8/7k/8/1pP5/7K/8/8 b - c3 0 1") + self.assertEqual(self.tablebase.probe_dtm(board), 19) + class SvgTestCase(unittest.TestCase): From 06de70e2e87969743dfa2196db1e2cbe687a08a8 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 24 Feb 2025 21:52:23 +0100 Subject: [PATCH 235/250] Fix checkmating ep capture in chess.gaviota.PythonTablebase --- chess/gaviota.py | 17 ++++++++++------- test.py | 10 ++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 83fb7bb64..281df836b 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -1493,8 +1493,8 @@ def probe_dtm(self, board: chess.Board) -> int: Probes for depth to mate information. The absolute value is the number of half-moves until forced mate - (or ``0`` in drawn positions). The value is positive if the - side to move is winning, otherwise it is negative. + (or ``0`` in drawn or checkmated positions). The value is positive if + the side to move is winning, otherwise it is negative or 0. In the example position, white to move will get mated in 10 half-moves: @@ -1532,11 +1532,14 @@ def probe_dtm(self, board: chess.Board) -> int: try: board.push(move) - child_dtm = -self._probe_dtm_no_ep(board) - if child_dtm > 0: - child_dtm += 1 - elif child_dtm < 0: - child_dtm -= 1 + if board.is_checkmate(): + child_dtm = 1 + else: + child_dtm = -self._probe_dtm_no_ep(board) + if child_dtm > 0: + child_dtm += 1 + elif child_dtm < 0: + child_dtm -= 1 dtm = min(dtm, child_dtm) if dtm * child_dtm > 0 else max(dtm, child_dtm) finally: diff --git a/test.py b/test.py index 7a3a3cdef..c120c049f 100755 --- a/test.py +++ b/test.py @@ -4353,6 +4353,16 @@ def test_ep_is_best(self): board = chess.Board("8/8/7k/8/1pP5/7K/8/8 b - c3 0 1") self.assertEqual(self.tablebase.probe_dtm(board), 19) + @catchAndSkip(chess.gaviota.MissingTableError, "need KQPvKP.gtb.cp4") + def test_ep_is_mate(self): + # The resulting mate. + board = chess.Board("5Q2/7k/6P1/5K2/8/8/8/8 b - - 0 1") + self.assertEqual(self.tablebase.probe_dtm(board), 0) + + # Ep leads to the previously tested mate position. + board = chess.Board("5Q2/7k/8/5KpP/8/8/8/8 w - g6 0 1") + self.assertEqual(self.tablebase.probe_dtm(board), 1) + class SvgTestCase(unittest.TestCase): From 45f616fae51a2b08ca4b4d0c01ddddf175d81ff9 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 25 Feb 2025 20:05:16 +0100 Subject: [PATCH 236/250] Supprt Python 3.13 --- .github/workflows/test.yml | 8 ++++---- setup.py | 1 + tox.ini | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 035b7f3d1..22d3b278a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: "3.12" + python-version: "3.13" - run: pip install -e . - run: python examples/perft/perft.py -t 1 examples/perft/random.perft --max-nodes 10000 - run: python examples/perft/perft.py -t 1 examples/perft/chess960.perft --max-nodes 100000 @@ -39,7 +39,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -59,7 +59,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: "3.12" + python-version: "3.13" - run: sudo apt-get update && sudo apt-get install -y docutils-common - run: python setup.py --long-description | rst2html --strict --no-raw > /dev/null - run: pip install -e . diff --git a/setup.py b/setup.py index b825adb44..9d6aa8c58 100755 --- a/setup.py +++ b/setup.py @@ -83,6 +83,7 @@ def read_description(): "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Games/Entertainment :: Board Games", "Topic :: Games/Entertainment :: Turn Based Strategy", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 8d8033676..5970b2c79 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py39,py310,py311 +envlist = py38,py39,py310,py311,py312,py313 [testenv] passenv = LD_LIBRARY_PATH From b3c1f62c82b5fc40b14fa33bc9edd31cef68a944 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Tue, 25 Feb 2025 19:20:27 +0100 Subject: [PATCH 237/250] Prepare 1.11.2 --- CHANGELOG.rst | 8 ++++++++ chess/__init__.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 05b899a20..03a9555d1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ Changelog for python-chess ========================== +New in v1.11.2 (25th Feb 2025) +------------------------------ + +Bugfixes: + +* Fix ``chess.gaviota.PythonTablebase`` does not properly resolve positions + where en passant captures are the best move. + New in v1.11.1 (9th Oct 2024) ----------------------------- diff --git a/chess/__init__.py b/chess/__init__.py index 8d0a68258..268f91cd5 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -11,7 +11,7 @@ __email__ = "niklas.fiekas@backscattering.de" -__version__ = "1.11.1" +__version__ = "1.11.2" import collections import copy From 2b8b0eb06accff3c4dea2e1cec108b3900a4f1d5 Mon Sep 17 00:00:00 2001 From: Mark Harrison Date: Mon, 24 Mar 2025 01:54:37 -0700 Subject: [PATCH 238/250] Add some missing docstrings This should cause these methods to appear in the readthedocs docs. --- chess/__init__.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/chess/__init__.py b/chess/__init__.py index 268f91cd5..28bcad0cd 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -1810,11 +1810,13 @@ def ply(self) -> int: return 2 * (self.fullmove_number - 1) + (self.turn == BLACK) def remove_piece_at(self, square: Square) -> Optional[Piece]: + """Remove a piece, if any, from the given square and return the removed piece.""" piece = super().remove_piece_at(square) self.clear_stack() return piece def set_piece_at(self, square: Square, piece: Optional[Piece], promoted: bool = False) -> None: + """Place a piece on a square.""" super().set_piece_at(square, piece, promoted=promoted) self.clear_stack() @@ -1998,6 +2000,7 @@ def is_pseudo_legal(self, move: Move) -> bool: return bool(self.attacks_mask(move.from_square) & to_mask) def is_legal(self, move: Move) -> bool: + """Check if a move is legal in the current position.""" return not self.is_variant_end() and self.is_pseudo_legal(move) and not self.is_into_check(move) def is_variant_end(self) -> bool: @@ -2034,9 +2037,27 @@ def is_variant_draw(self) -> bool: return False def is_game_over(self, *, claim_draw: bool = False) -> bool: + """ + Check if the game is over by any rule. + + The game is not considered to be over by the + :func:`fifty-move rule ` or + :func:`threefold repetition `, + unless *claim_draw* is given. Note that checking the latter can be + slow. + """ return self.outcome(claim_draw=claim_draw) is not None def result(self, *, claim_draw: bool = False) -> str: + """ + Return the result of a game: 1-0, 0-1, 1/2-1/2, or *. + + The game is not considered to be over by the + :func:`fifty-move rule ` or + :func:`threefold repetition `, + unless *claim_draw* is given. Note that checking the latter can be + slow. + """ outcome = self.outcome(claim_draw=claim_draw) return outcome.result() if outcome else "*" From b2144c2564f740ea120d037e9ec6129d8a3bea2c Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 3 Oct 2025 23:01:01 +0200 Subject: [PATCH 239/250] Remove explicit CodeQL configuration --- .github/workflows/codeql.yml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index bc991c885..000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: CodeQL - -on: [push, pull_request] - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - steps: - - uses: actions/checkout@v4 - - uses: github/codeql-action/init@v3 - with: - languages: python - - uses: github/codeql-action/analyze@v3 From 760360b8ddb65129aea46f84d99b5491e6ed6435 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 3 Oct 2025 23:04:49 +0200 Subject: [PATCH 240/250] Explicitly specify CI workflow permissions --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 22d3b278a..9eca0fce3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,9 @@ name: Test on: [push, pull_request] +permissions: + contents: read + jobs: test: strategy: From 6b1cfedd442a05767ee28c7752a800ad4190f423 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 3 Oct 2025 23:14:56 +0200 Subject: [PATCH 241/250] Fix chess.gaviota bytearray usage does not pass mypy 1.18 --- chess/gaviota.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index 281df836b..dc19557cd 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -1716,7 +1716,7 @@ def _tb_probe(self, req: Request) -> int: z = self.egtb_block_getsize_zipped(req.egkey, block) self.egtb_block_park(req.egkey, block, stream) - buffer_zipped = stream.read(z) + buffer_zipped: bytearray | bytes = stream.read(z) if buffer_zipped[0] == 0: # If flag is zero, plain LZMA is following. From 71f5a21fe9a83770081fa9f7d2deb3835db984e4 Mon Sep 17 00:00:00 2001 From: Jackson Hall Date: Sat, 4 Oct 2025 16:52:41 -0400 Subject: [PATCH 242/250] Add and use rank/file constants --- chess/__init__.py | 80 +++++++++++++++++++++++++++++------------------ chess/gaviota.py | 8 ++--- chess/syzygy.py | 2 +- 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/chess/__init__.py b/chess/__init__.py index 28bcad0cd..3d3dad4f0 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -64,8 +64,28 @@ def piece_name(piece_type: PieceType) -> str: "P": "♙", "p": "♟", } +File: TypeAlias = int +FILE_A: File = 0 +FILE_B: File = 1 +FILE_C: File = 2 +FILE_D: File = 3 +FILE_E: File = 4 +FILE_F: File = 5 +FILE_G: File = 6 +FILE_H: File = 7 +FILES = [FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H] FILE_NAMES = ["a", "b", "c", "d", "e", "f", "g", "h"] +Rank: TypeAlias = int +RANK_1: Rank = 0 +RANK_2: Rank = 1 +RANK_3: Rank = 2 +RANK_4: Rank = 3 +RANK_5: Rank = 4 +RANK_6: Rank = 5 +RANK_7: Rank = 6 +RANK_8: Rank = 7 +RANKS = [RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8] RANK_NAMES = ["1", "2", "3", "4", "5", "6", "7", "8"] STARTING_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" @@ -251,15 +271,15 @@ def square_name(square: Square) -> str: """Gets the name of the square, like ``a3``.""" return SQUARE_NAMES[square] -def square(file_index: int, rank_index: int) -> Square: +def square(file_index: File, rank_index: Rank) -> Square: """Gets a square number by file and rank index.""" return rank_index * 8 + file_index -def square_file(square: Square) -> int: +def square_file(square: Square) -> File: """Gets the file index of the square where ``0`` is the a-file.""" return square & 7 -def square_rank(square: Square) -> int: +def square_rank(square: Square) -> Rank: """Gets the rank index of the square where ``0`` is the first rank.""" return square >> 3 @@ -376,24 +396,24 @@ def square_mirror(square: Square) -> Square: BB_LIGHT_SQUARES: Bitboard = 0x55aa_55aa_55aa_55aa BB_DARK_SQUARES: Bitboard = 0xaa55_aa55_aa55_aa55 -BB_FILE_A: Bitboard = 0x0101_0101_0101_0101 << 0 -BB_FILE_B: Bitboard = 0x0101_0101_0101_0101 << 1 -BB_FILE_C: Bitboard = 0x0101_0101_0101_0101 << 2 -BB_FILE_D: Bitboard = 0x0101_0101_0101_0101 << 3 -BB_FILE_E: Bitboard = 0x0101_0101_0101_0101 << 4 -BB_FILE_F: Bitboard = 0x0101_0101_0101_0101 << 5 -BB_FILE_G: Bitboard = 0x0101_0101_0101_0101 << 6 -BB_FILE_H: Bitboard = 0x0101_0101_0101_0101 << 7 +BB_FILE_A: Bitboard = 0x0101_0101_0101_0101 << FILE_A +BB_FILE_B: Bitboard = 0x0101_0101_0101_0101 << FILE_B +BB_FILE_C: Bitboard = 0x0101_0101_0101_0101 << FILE_C +BB_FILE_D: Bitboard = 0x0101_0101_0101_0101 << FILE_D +BB_FILE_E: Bitboard = 0x0101_0101_0101_0101 << FILE_E +BB_FILE_F: Bitboard = 0x0101_0101_0101_0101 << FILE_F +BB_FILE_G: Bitboard = 0x0101_0101_0101_0101 << FILE_G +BB_FILE_H: Bitboard = 0x0101_0101_0101_0101 << FILE_H BB_FILES: List[Bitboard] = [BB_FILE_A, BB_FILE_B, BB_FILE_C, BB_FILE_D, BB_FILE_E, BB_FILE_F, BB_FILE_G, BB_FILE_H] -BB_RANK_1: Bitboard = 0xff << (8 * 0) -BB_RANK_2: Bitboard = 0xff << (8 * 1) -BB_RANK_3: Bitboard = 0xff << (8 * 2) -BB_RANK_4: Bitboard = 0xff << (8 * 3) -BB_RANK_5: Bitboard = 0xff << (8 * 4) -BB_RANK_6: Bitboard = 0xff << (8 * 5) -BB_RANK_7: Bitboard = 0xff << (8 * 6) -BB_RANK_8: Bitboard = 0xff << (8 * 7) +BB_RANK_1: Bitboard = 0xff << (8 * RANK_1) +BB_RANK_2: Bitboard = 0xff << (8 * RANK_2) +BB_RANK_3: Bitboard = 0xff << (8 * RANK_3) +BB_RANK_4: Bitboard = 0xff << (8 * RANK_4) +BB_RANK_5: Bitboard = 0xff << (8 * RANK_5) +BB_RANK_6: Bitboard = 0xff << (8 * RANK_6) +BB_RANK_7: Bitboard = 0xff << (8 * RANK_7) +BB_RANK_8: Bitboard = 0xff << (8 * RANK_8) BB_RANKS: List[Bitboard] = [BB_RANK_1, BB_RANK_2, BB_RANK_3, BB_RANK_4, BB_RANK_5, BB_RANK_6, BB_RANK_7, BB_RANK_8] BB_BACKRANKS: Bitboard = BB_RANK_1 | BB_RANK_8 @@ -1847,7 +1867,7 @@ def generate_pseudo_legal_moves(self, from_mask: Bitboard = BB_ALL, to_mask: Bit self.occupied_co[not self.turn] & to_mask) for to_square in scan_reversed(targets): - if square_rank(to_square) in [0, 7]: + if square_rank(to_square) in [RANK_1, RANK_8]: yield Move(from_square, to_square, QUEEN) yield Move(from_square, to_square, ROOK) yield Move(from_square, to_square, BISHOP) @@ -1870,7 +1890,7 @@ def generate_pseudo_legal_moves(self, from_mask: Bitboard = BB_ALL, to_mask: Bit for to_square in scan_reversed(single_moves): from_square = to_square + (8 if self.turn == BLACK else -8) - if square_rank(to_square) in [0, 7]: + if square_rank(to_square) in [RANK_1, RANK_8]: yield Move(from_square, to_square, QUEEN) yield Move(from_square, to_square, ROOK) yield Move(from_square, to_square, BISHOP) @@ -1897,7 +1917,7 @@ def generate_pseudo_legal_ep(self, from_mask: Bitboard = BB_ALL, to_mask: Bitboa capturers = ( self.pawns & self.occupied_co[self.turn] & from_mask & BB_PAWN_ATTACKS[not self.turn][self.ep_square] & - BB_RANKS[4 if self.turn else 3]) + BB_RANKS[RANK_5 if self.turn else RANK_4]) for capturer in scan_reversed(capturers): yield Move(capturer, self.ep_square) @@ -1977,9 +1997,9 @@ def is_pseudo_legal(self, move: Move) -> bool: if piece != PAWN: return False - if self.turn == WHITE and square_rank(move.to_square) != 7: + if self.turn == WHITE and square_rank(move.to_square) != RANK_8: return False - elif self.turn == BLACK and square_rank(move.to_square) != 0: + elif self.turn == BLACK and square_rank(move.to_square) != RANK_1: return False # Handle castling. @@ -2401,18 +2421,18 @@ def push(self, move: Move) -> None: else: self.castling_rights &= ~BB_RANK_8 elif captured_piece_type == KING and not self.promoted & to_bb: - if self.turn == WHITE and square_rank(move.to_square) == 7: + if self.turn == WHITE and square_rank(move.to_square) == RANK_8: self.castling_rights &= ~BB_RANK_8 - elif self.turn == BLACK and square_rank(move.to_square) == 0: + elif self.turn == BLACK and square_rank(move.to_square) == RANK_1: self.castling_rights &= ~BB_RANK_1 # Handle special pawn moves. if piece_type == PAWN: diff = move.to_square - move.from_square - if diff == 16 and square_rank(move.from_square) == 1: + if diff == 16 and square_rank(move.from_square) == RANK_2: self.ep_square = move.from_square + 8 - elif diff == -16 and square_rank(move.from_square) == 6: + elif diff == -16 and square_rank(move.from_square) == RANK_7: self.ep_square = move.from_square - 8 elif move.to_square == ep_square and abs(diff) in [7, 9] and not captured_piece_type: # Remove pawns captured en passant. @@ -3605,11 +3625,11 @@ def _valid_ep_square(self) -> Optional[Square]: return None if self.turn == WHITE: - ep_rank = 5 + ep_rank = RANK_6 pawn_mask = shift_down(BB_SQUARES[self.ep_square]) seventh_rank_mask = shift_up(BB_SQUARES[self.ep_square]) else: - ep_rank = 2 + ep_rank = RANK_3 pawn_mask = shift_up(BB_SQUARES[self.ep_square]) seventh_rank_mask = shift_down(BB_SQUARES[self.ep_square]) diff --git a/chess/gaviota.py b/chess/gaviota.py index dc19557cd..c352a27ca 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -110,12 +110,12 @@ def idx_is_empty(x: int) -> int: def flip_type(x: chess.Square, y: chess.Square) -> int: ret = 0 - if chess.square_file(x) > 3: + if chess.square_file(x) > chess.FILE_D: x = flip_we(x) y = flip_we(y) ret |= 1 - if chess.square_rank(x) > 3: + if chess.square_rank(x) > chess.RANK_4: x = flip_ns(x) y = flip_ns(y) ret |= 2 @@ -351,11 +351,11 @@ def init_ppidx() -> Tuple[List[List[int]], List[int], List[int]]: def norm_kkindex(x: chess.Square, y: chess.Square) -> Tuple[int, int]: - if chess.square_file(x) > 3: + if chess.square_file(x) > chess.FILE_D: x = flip_we(x) y = flip_we(y) - if chess.square_rank(x) > 3: + if chess.square_rank(x) > chess.RANK_4: x = flip_ns(x) y = flip_ns(y) diff --git a/chess/syzygy.py b/chess/syzygy.py index c61890550..0c6b7822c 100644 --- a/chess/syzygy.py +++ b/chess/syzygy.py @@ -761,7 +761,7 @@ def calc_symlen(self, d: PairsData, s: int, tmp: List[int]) -> None: d.symlen[s] = d.symlen[s1] + d.symlen[s2] + 1 tmp[s] = 1 - def pawn_file(self, pos: List[chess.Square]) -> int: + def pawn_file(self, pos: List[chess.Square]) -> chess.File: for i in range(1, self.pawns[0]): if FLAP[pos[0]] > FLAP[pos[i]]: pos[0], pos[i] = pos[i], pos[0] From bd8074d20e7aa667315b54470d0f3aae6390e69d Mon Sep 17 00:00:00 2001 From: Jackson Hall Date: Sat, 4 Oct 2025 20:47:45 -0400 Subject: [PATCH 243/250] Add `parse_file`/`parse_rank`, `file_name`/rank_name` --- chess/__init__.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/chess/__init__.py b/chess/__init__.py index 3d3dad4f0..84bfa632a 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -275,6 +275,32 @@ def square(file_index: File, rank_index: Rank) -> Square: """Gets a square number by file and rank index.""" return rank_index * 8 + file_index +def parse_file(name: str) -> File: + """ + Gets the file index for the given file *name* + (e.g., ``a`` returns ``0``). + + :raises: :exc:`ValueError` if the file name is invalid. + """ + return FILE_NAMES.index(name) + +def file_name(file: File) -> str: + """Gets the name of the file, like ``a``.""" + return FILE_NAMES[file] + +def parse_rank(name: str) -> File: + """ + Gets the rank index for the given rank *name* + (e.g., ``1`` returns ``0``). + + :raises: :exc:`ValueError` if the rank name is invalid. + """ + return FILE_NAMES.index(name) + +def rank_name(rank: Rank) -> str: + """Gets the name of the rank, like ``1``.""" + return FILE_NAMES[rank] + def square_file(square: Square) -> File: """Gets the file index of the square where ``0`` is the a-file.""" return square & 7 From 376d603694913a82bcb2efa594972a5fba5804f6 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 11 Oct 2025 09:20:54 +0200 Subject: [PATCH 244/250] Explicitly support Python 3.14 --- .github/workflows/test.yml | 24 ++++++++++++------------ setup.py | 1 + tox.ini | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9eca0fce3..6b31bce24 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,11 +10,11 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - run: .github/workflows/setup-${{ matrix.os }}.sh @@ -24,10 +24,10 @@ jobs: perft: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" - run: pip install -e . - run: python examples/perft/perft.py -t 1 examples/perft/random.perft --max-nodes 10000 - run: python examples/perft/perft.py -t 1 examples/perft/chess960.perft --max-nodes 100000 @@ -42,11 +42,11 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - run: pip install -e . @@ -59,10 +59,10 @@ jobs: readme: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" - run: sudo apt-get update && sudo apt-get install -y docutils-common - run: python setup.py --long-description | rst2html --strict --no-raw > /dev/null - run: pip install -e . diff --git a/setup.py b/setup.py index 9d6aa8c58..5815947cd 100755 --- a/setup.py +++ b/setup.py @@ -84,6 +84,7 @@ def read_description(): "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Games/Entertainment :: Board Games", "Topic :: Games/Entertainment :: Turn Based Strategy", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 5970b2c79..493a46feb 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py39,py310,py311,py312,py313 +envlist = py38,py39,py310,py311,py312,py313,py314 [testenv] passenv = LD_LIBRARY_PATH From e4386c2f1efcb686c1d6222681cc84d1f0b06ded Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 11 Oct 2025 15:25:33 +0200 Subject: [PATCH 245/250] Remove chess.engine.DefaultEventLoopPolicy (breaking change forced by Python) --- chess/engine.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/chess/engine.py b/chess/engine.py index b979b278f..8482c31ba 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -50,10 +50,6 @@ def override(fn: F, /) -> F: MANAGED_OPTIONS = ["uci_chess960", "uci_variant", "multipv", "ponder"] -# No longer needed, but alias kept around for compatibility. -EventLoopPolicy = asyncio.DefaultEventLoopPolicy - - def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Coroutine[Any, Any, None]], *, name: Optional[str] = None, debug: Optional[bool] = None) -> T: """ Runs ``coroutine(future)`` in a new event loop on a background thread. From e974a37e52a59709a0988872a12c1f01244a8c15 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 11 Oct 2025 15:30:39 +0200 Subject: [PATCH 246/250] Fix test_sf_forced_mates() failing due to ambiguous mate --- test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.py b/test.py index c120c049f..2ebd357d0 100755 --- a/test.py +++ b/test.py @@ -3079,7 +3079,7 @@ def test_sf_forced_mates(self): for epd in epds: operations = board.set_epd(epd) - result = engine.play(board, chess.engine.Limit(mate=5), game=object()) + result = engine.play(board, chess.engine.Limit(mate=3), game=object()) self.assertIn(result.move, operations["bm"], operations["id"]) @catchAndSkip(FileNotFoundError, "need stockfish") From 8412bd56a282f7fe7071a8b1788b6b791d5e7b0e Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 11 Oct 2025 15:33:30 +0200 Subject: [PATCH 247/250] asyncio.iscoroutinefunction() -> inspect.iscoroutinefunction() --- chess/engine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chess/engine.py b/chess/engine.py index 8482c31ba..913940190 100644 --- a/chess/engine.py +++ b/chess/engine.py @@ -8,6 +8,7 @@ import copy import dataclasses import enum +import inspect import logging import math import shlex @@ -58,7 +59,7 @@ def run_in_background(coroutine: Callable[[concurrent.futures.Future[T]], Corout The coroutine and all remaining tasks continue running in the background until complete. """ - assert asyncio.iscoroutinefunction(coroutine) + assert inspect.iscoroutinefunction(coroutine) future: concurrent.futures.Future[T] = concurrent.futures.Future() From 624d3a730c180e749ea04a473a828b9c31ff52a4 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Sat, 11 Oct 2025 15:38:19 +0200 Subject: [PATCH 248/250] Do not fail-fast matrix jobs that may have interesting results --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6b31bce24..9d0880bb4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + fail-fast: false runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 @@ -43,6 +44,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + fail-fast: false runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 From 4d9b3bfd860bfa95731d4e208fd98c7c10a15533 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 27 Oct 2025 21:24:16 +0100 Subject: [PATCH 249/250] Fix Gaviota tables opened as writable (fixes #1166) --- chess/gaviota.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chess/gaviota.py b/chess/gaviota.py index c352a27ca..8beb18d4d 100644 --- a/chess/gaviota.py +++ b/chess/gaviota.py @@ -1663,7 +1663,7 @@ def _open_tablebase(self, req: Request) -> BinaryIO: if stream is None: path = self.available_tables[req.egkey] - stream = open(path, "rb+") + stream = open(path, "rb") self.egtb_loadindexes(req.egkey, stream) self.streams[req.egkey] = stream From f8575f962caf3fcddcf95d935d1d75a1cceb586b Mon Sep 17 00:00:00 2001 From: Jackson Hall Date: Sun, 2 Nov 2025 18:46:03 -0500 Subject: [PATCH 250/250] Add `Board.gives_checkmate()` --- chess/__init__.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/chess/__init__.py b/chess/__init__.py index 84bfa632a..b51c31ca3 100644 --- a/chess/__init__.py +++ b/chess/__init__.py @@ -1980,6 +1980,17 @@ def gives_check(self, move: Move) -> bool: finally: self.pop() + def gives_checkmate(self, move: Move) -> bool: + """ + Probes if the given move would put the opponent in checkmate. The move + must be at least pseudo-legal. + """ + self.push(move) + try: + return self.is_checkmate() + finally: + self.pop() + def is_into_check(self, move: Move) -> bool: king = self.king(self.turn) if king is None: