niklasf / python-chess

A chess library for Python, with move generation and validation, PGN parsing and writing, Polyglot opening book reading, Gaviota tablebase probing, Syzygy tablebase probing, and UCI/XBoard engine communication
https://python-chess.readthedocs.io/en/latest/
GNU General Public License v3.0
2.4k stars 521 forks source link

Add flipping functions #335

Closed oscardssmith closed 5 years ago

oscardssmith commented 5 years ago

It would be really nice to have functions to flip a board vertically, horizontally, or along a diagonal. These are fairly simple conceptual operations, but a pain to implement when you want them.

niklasf commented 5 years ago

Agreed, that sounds like a useful feature.

Some groundwork is laid already: There's an undocumented board.transform(f) that takes a function that changes bitboards. For example flipped_vertically = board.transform(chess.bswap). It remains to implement functions that flip a bitboard horizontally or on diagonals, and make these discoverable.

oscardssmith commented 5 years ago

These aren't especially efficient but they work

def flip_horiz():
    piece_map = board.piece_map()
    new_map = {i^7: p for i, p in piece_map.items()}
    board.set_piece_map(new_map)
def flip_vert():
        piece_map = board.piece_map()
        new_map = {i^56: p for i, p in piece_map.items()}
        board.set_piece_map(new_map)
def flip_diag()
        piece_map = board.piece_map()
        new_map = {8*(i%8) + i//8 : p for i, p in piece_map.items()}
        board.set_piece_map(new_map)
niklasf commented 5 years ago

Thanks. I added bitboard based implementations. Your functions are now equivalent to:

def flip_horiz(board):
    board.apply_transform(chess.flip_horizontal)

def flip_vert(board):
    board.apply_transform(chess.flip_vertical)

def flip_diag(board):
    board.apply_transform(chess.flip_diag)

def flip_anti_diag(board):
    board.apply_transform(chess.flip_anti_diag)

Example:

>>> import chess
>>> s = chess.SquareSet(0x1e2222120e0a1222)
>>> print(s)
. 1 1 1 1 . . .
. 1 . . . 1 . .
. 1 . . . 1 . .
. 1 . . 1 . . .
. 1 1 1 . . . .
. 1 . 1 . . . .
. 1 . . 1 . . .
. 1 . . . 1 . .
>>> print(chess.flip_horizontal(s))
. . . 1 1 1 1 .
. . 1 . . . 1 .
. . 1 . . . 1 .
. . . 1 . . 1 .
. . . . 1 1 1 .
. . . . 1 . 1 .
. . . 1 . . 1 .
. . 1 . . . 1 .
>>> print(chess.flip_vertical(s))
. 1 . . . 1 . .
. 1 . . 1 . . .
. 1 . 1 . . . .
. 1 1 1 . . . .
. 1 . . 1 . . .
. 1 . . . 1 . .
. 1 . . . 1 . .
. 1 1 1 1 . . .
>>> print(chess.flip_diag(s))
. . . . . . . .
. . . . . . . .
1 . . . . 1 1 .
. 1 . . 1 . . 1
. . 1 1 . . . 1
. . . 1 . . . 1
1 1 1 1 1 1 1 1
. . . . . . . .
>>> print(chess.flip_anti_diag(s))
. . . . . . . .
1 1 1 1 1 1 1 1
1 . . . 1 . . .
1 . . . 1 1 . .
1 . . 1 . . 1 .
. 1 1 . . . . 1
. . . . . . . .
. . . . . . . .
oscardssmith commented 5 years ago

thanks so much for all your help so far