|
1 | | -from typing import Iterable, Union, SupportsInt, Iterator, Callable, List, Tuple, Dict, Optional |
| 1 | +from typing import Iterable, Union, SupportsInt, Iterator, Callable, List, Tuple, Dict, TypeVar,Optional |
2 | 2 | import copy |
3 | 3 | import dataclasses |
4 | 4 | import enum |
@@ -306,6 +306,30 @@ def square_mirror(square: Square) -> Square: |
306 | 306 | BB_START_OCCUPIED = 0x3fe00415540000aaa0801ff |
307 | 307 |
|
308 | 308 |
|
| 309 | +def flip_vertical(bb: BitBoard) -> BitBoard: |
| 310 | + # https://www.chessprogramming.org/Flipping_Mirroring_and_Rotating#FlipVertically |
| 311 | + K1 = 0x1FF00003FE00FF80001FF |
| 312 | + K2 = 0xFF8000000007FC0000 |
| 313 | + bb = ((bb >> 9) & K1) | ((bb & K1) << 9) | (bb & K2) |
| 314 | + K3 = 0x7FFFE0000003FFFF |
| 315 | + bb = (bb >> 9*3) & K3 | (bb & K3) << 9*3 | (bb & K2) |
| 316 | + |
| 317 | + K4 = 0x1FFFFFFFFFFF |
| 318 | + bb= (bb >> 9*5) & K4 | (bb & K4) << 9*5 |
| 319 | + |
| 320 | + return bb |
| 321 | + |
| 322 | +def flip_horizontal(bb: BitBoard) -> BitBoard: |
| 323 | + # https://www.chessprogramming.org/Flipping_Mirroring_and_Rotating#MirrorHorizontally |
| 324 | + FH1 = 0x14AA552A954AA552A954AA5 |
| 325 | + FH2 = 0x2010080402010080402010 |
| 326 | + FH3 = 0xC6633198CC6633198CC663 |
| 327 | + FH4 = 0x1E0F0783C1E0F0783C1E0F |
| 328 | + bb = ((bb >> 1) & FH1) | ((bb & FH1) << 1) | (bb & FH2) |
| 329 | + bb = ((bb >> 2) & FH3) | ((bb & FH3) << 2) | (bb & FH2) |
| 330 | + bb = ((bb >> 5) & FH4) | ((bb & FH4) << 5) |
| 331 | + return bb |
| 332 | + |
309 | 333 | def _sliding_attacks(square: Square, occupied: BitBoard, deltas: Iterable[int]): |
310 | 334 | attacks = BB_EMPTY |
311 | 335 |
|
@@ -617,6 +641,7 @@ def null(cls): |
617 | 641 | def __hash__(self): |
618 | 642 | return hash((self.from_square, self.to_square)) |
619 | 643 |
|
| 644 | +BaseBoardT = TypeVar("BaseBoardT", bound="BaseBoard") |
620 | 645 |
|
621 | 646 | class BaseBoard: |
622 | 647 | def __init__(self, board_fen: Optional[str] = STARTING_BOARD_FEN): |
@@ -907,6 +932,55 @@ def attacks_mask(self, square: Square) -> BitBoard: |
907 | 932 | return _cannon_attacks(square, self.occupied) |
908 | 933 | return 0 |
909 | 934 |
|
| 935 | + |
| 936 | + def apply_transform(self, f: Callable[[BitBoard], BitBoard]) -> None: |
| 937 | + self.pawns = f(self.pawns) |
| 938 | + self.knights = f(self.knights) |
| 939 | + self.bishops = f(self.bishops) |
| 940 | + self.rooks = f(self.rooks) |
| 941 | + self.advisors = f(self.advisors) |
| 942 | + self.kings = f(self.kings) |
| 943 | + self.cannons = f(self.cannons) |
| 944 | + |
| 945 | + self.occupied_co[RED] = f(self.occupied_co[RED]) |
| 946 | + self.occupied_co[BLACK] = f(self.occupied_co[BLACK]) |
| 947 | + self.occupied = f(self.occupied) |
| 948 | + |
| 949 | + |
| 950 | + def transform(self: BaseBoardT, f: Callable[[BitBoard], BitBoard]) -> BaseBoardT: |
| 951 | + """ |
| 952 | + Returns a transformed copy of the board (without move stack) |
| 953 | + by applying a bitboard transformation function. |
| 954 | +
|
| 955 | + Available transformations include :func:`chess.flip_vertical()`, |
| 956 | + :func:`chess.flip_horizontal()`, :func:`chess.flip_vertical()`, |
| 957 | +
|
| 958 | +
|
| 959 | + Alternatively, :func:`~chess.BaseBoard.apply_transform()` can be used |
| 960 | + to apply the transformation on the board. |
| 961 | + """ |
| 962 | + board = self.copy() |
| 963 | + board.apply_transform(f) |
| 964 | + return board |
| 965 | + |
| 966 | + def apply_mirror(self: BaseBoardT) -> None: |
| 967 | + self.apply_transform(flip_vertical) |
| 968 | + self.occupied_co[RED], self.occupied_co[BLACK] = self.occupied_co[BLACK], self.occupied_co[RED] |
| 969 | + |
| 970 | + def mirror(self: BaseBoardT) -> BaseBoardT: |
| 971 | + """ |
| 972 | + Returns a mirrored copy of the board (without move stack). |
| 973 | +
|
| 974 | + The board is mirrored vertically and piece colors are swapped, so that |
| 975 | + the position is equivalent modulo color. |
| 976 | +
|
| 977 | + Alternatively, :func:`~chess.BaseBoard.apply_mirror()` can be used |
| 978 | + to mirror the board. |
| 979 | + """ |
| 980 | + board = self.copy() |
| 981 | + board.apply_mirror() |
| 982 | + return board |
| 983 | + |
910 | 984 | def attacks(self, square: Square): |
911 | 985 | """ |
912 | 986 | Gets the set of attacked squares from the given square. |
|
0 commit comments