This is the scholars mate in python-chess:
>>> import chess
>>> board = chess.Bitboard()
>>> board.push_san("e4")
Move.from_uci('e2e4')
>>> board.push_san("e5")
Move.from_uci('e7e5')
>>> board.push_san("Qh5")
Move.from_uci('d1h5')
>>> board.push_san("Nc6")
Move.from_uci('b8c6')
>>> board.push_san("Bc4")
Move.from_uci('f1c4')
>>> board.push_san("Nf6")
Move.from_uci('g8f6')
>>> board.push_san("Qxf7")
Move.from_uci('h5f7')
>>> board.is_checkmate()
True
https://python-chess.readthedocs.org/en/latest/
Supports Python 2.7 and Python 3.
Legal move generator and move validation. This includes all castling rules and en-passant captures.
>>> chess.Move.from_uci("a8a1") in board.legal_moves False
Make and unmake moves.
>>> Qf7 = board.pop() # Unmake last move (Qf7#) >>> Qf7 Move.from_uci('h5f7') >>> board.push(Qf7) # Restore
Detects checkmates, stalemates and draws by insufficient material.
>>> board.is_stalemate() False >>> board.is_insufficient_material() False >>> board.is_game_over() True >>> board.halfmove_clock 0
Detects repititions. Has a half move clock.
>>> board.can_claim_threefold_repitition() False >>> board.halfmove_clock 0 >>> board.can_claim_fifty_moves() False >>> board.can_claim_draw() False
With the new rules from July 2014 a game ends drawn (even without a claim) once a fivefold repitition occurs or if there are 75 moves without a pawn push or capture. Other ways of ending a game take precedence.
>>> board.is_fivefold_repitition() False >>> board.is_seventyfive_moves() False
Detects checks and attacks.
>>> board.is_check() True >>> board.is_attacked_by(chess.WHITE, chess.E8) True >>> attackers = board.attackers(chess.WHITE, chess.F3) >>> attackers SquareSet(0b100000001000000) >>> chess.G2 in attackers True
Parses and creates SAN representation of moves.
>>> board = chess.Bitboard() >>> board.san(chess.Move(chess.E2, chess.E4)) 'e4'
Parses and creates FENs.
>>> board.fen() 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1' >>> board = chess.Bitboard("8/8/8/2k5/4K3/8/8/8 w - - 4 45") >>> board.piece_at(chess.C5) Piece.from_symbol('k')
Parses and creates EPDs.
>>> board = chess.Bitboard() >>> board.epd(bm=chess.Move.from_uci("d2d4")) 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - bm d4;' >>> ops = board.set_epd("1k1r4/pp1b1R2/3q2pp/4p3/2B5/4Q3/PPP2B2/2K5 b - - bm Qd1+; id \"BK.01\";") >>> ops == {'bm': chess.Move.from_uci('d6d1'), 'id': 'BK.01'} True
Read Polyglot opening books.
>>> import chess.polyglot >>> book = chess.polyglot.open_reader("data/opening-books/performance.bin") >>> board = chess.Bitboard() >>> first_entry = next(book.get_entries_for_position(board)) >>> first_entry.move() Move.from_uci('e2e4') >>> first_entry.learn 0 >>> first_entry.weight 1 >>> book.close()
Read and write PGNs. Supports headers, comments, NAGs and a tree of variations.
>>> import chess.pgn >>> from __future__ import print_function # Python 2 compability for >>> # this example. >>> pgn = open("data/games/molinari-bordais-1979.pgn") >>> first_game = chess.pgn.read_game(pgn) >>> pgn.close() >>> first_game.headers["White"] 'Molinari' >>> first_game.headers["Black"] 'Bordais' >>> # Iterate through the mainline of this embarrasingly short game. >>> node = first_game >>> while node.variations: ... next_node = node.variation(0) ... print(node.board().san(next_node.move)) ... node = next_node e4 c5 c4 Nc6 Ne2 Nf6 Nbc3 Nb4 g3 Nd3# >>> first_game.headers["Result"] '0-1'
Probe Syzygy endgame tablebases.
>>> import chess.syzygy >>> tablebases = chess.syzygy.Tablebases("data/syzygy") >>> # Black to move is losing in 53 half moves (distance to zero) in this >>> # KNBvK endgame. >>> board = chess.Bitboard("8/2K5/4B3/3N4/8/8/4k3/8 b - - 0 1") >>> tablebases.probe_dtz(board) -53 >>> tablebases.close()
Communicate with an UCI engine.
>>> import chess.uci >>> import time >>> engine = chess.uci.popen_engine("/usr/games/stockfish") >>> engine.uci() >>> engine.author 'Tord Romstad, Marco Costalba and Joona Kiiski' >>> # Synchronous mode. >>> board = chess.Bitboard("1k1r4/pp1b1R2/3q2pp/4p3/2B5/4Q3/PPP2B2/2K5 b - - 0 1") >>> engine.position(board) >>> engine.go(movetime=2000) # Gets tuple of bestmove and ponder move. BestMove(bestmove=Move.from_uci('d6d1'), ponder=Move.from_uci('c1d1')) >>> # Synchronous communication, but search in background. >>> engine.go(infinite=True) >>> time.sleep(2) >>> engine.stop() BestMove(bestmove=Move.from_uci('d6d1'), ponder=Move.from_uci('c1d1')) >>> # Asynchronous mode. >>> def callback(command): ... bestmove, ponder = command.result() ... assert bestmove == chess.Move.from_uci('d6d1') ... >>> command = engine.go(movetime=2000, async_callback=callback) >>> command.done() False >>> command.result() BestMove(bestmove=Move.from_uci('d6d1'), ponder=Move.from_uci('c1d1')) >>> command.done() True
python-chess is not intended to be used by serious chess engines where performance is critical. The goal is rather to create a simple and relatively highlevel library.
You can install the gmpy2 or gmpy (https://code.google.com/p/gmpy/) modules in order to get a slight performance boost on basic operations like bit scans and population counts.
python-chess will only ever import very basic general (non-chess-related) operations from native libraries. All logic is pure Python. There will always be pure Python fallbacks.
With pip:
sudo pip install python-chess
From current source code:
python setup.py build sudo python setup.py install
If you like, let me know if you are creating something intresting with python-chess, for example:
- a stand alone chess computer based on DGT board - http://www.picochess.org/
- a cross platform chess GUI - https://asdfjkl.github.io/jerry/
- a website to probe Syzygy endgame tablebases - https://syzygy-tables.info/
python-chess is licensed under the GPL3. See the LICENSE file for the full copyright and license information.
Thanks to the developers of http://chessx.sourceforge.net/. Some of the core bitboard move generation parts are ported from there.
Thanks to Ronald de Man for his Syzygy endgame tablebases (https://github.com/syzygy1/tb). The probing code in python-chess is very directly ported from his C probing code.