Note
Go to the end to download the full example code.
Basic Walkthrough#
First, lets import everything from bulletchess
from bulletchess import *
The Board()
constructor returns a Board
representing the starting position.
board = Board()
board
The Board
class defines Board._repr_html_()
, which allows positions to be rendered
like the above in Jupyter note books, or Sphinx documentation like this page.
For displaying a Board
as plain text, we use Board.__str__()
.
print(str(board))
r n b q k b n r
p p p p p p p p
- - - - - - - -
- - - - - - - -
- - - - - - - -
- - - - - - - -
P P P P P P P P
R N B Q K B N R
Other positions can be specified by either using Board.from_fen()
,
board = Board.from_fen("rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2")
board
Or by assigning Piece
locations manually. We can use Board.empty()
to start from a clean slate.
board = Board.empty()
board
And then assign a Piece
to each Square
.
board[G2] = Piece(WHITE, KING)
board[F2] = Piece(WHITE, PAWN)
board[G3] = Piece(WHITE, PAWN)
board[H2] = Piece(WHITE, PAWN)
board[B3] = Piece(WHITE, ROOK)
board[F7] = Piece(BLACK, KING)
board[D7] = Piece(BLACK, ROOK)
board[F6] = Piece(BLACK, PAWN)
board[G7] = Piece(BLACK, PAWN)
board
We can get the FEN of this position with Board.fen()
. We might want to set the half-move clock
and full-move number for this endgame position. Let’s also make it black’s turn.
board.halfmove_clock = 3
board.fullmove_number = 43
board.turn = BLACK
board.fen()
'8/3r1kp1/5p2/8/8/1R4P1/5PKP/8 b - - 3 43'
Indexing a Board
with a Color
, PieceType
, or both returns Bitboard
of squares with the relevant pieces. A Bitboard
is simply an efficient representation
of a set of squares.
print(board[WHITE])
print(board[ROOK])
print(board[BLACK, PAWN])
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0
0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
We can generate legal Move
objects for this position with Board.legal_moves()
moves = board.legal_moves()
print(moves)
[<Move: f6f5>, <Move: d7d1>, <Move: d7d2>, <Move: d7d3>, <Move: d7d4>, <Move: d7d5>, <Move: d7d6>, <Move: d7a7>, <Move: d7b7>, <Move: d7c7>, <Move: d7e7>, <Move: d7d8>, <Move: f7e6>, <Move: f7g6>, <Move: f7e7>, <Move: f7e8>, <Move: f7f8>, <Move: f7g8>, <Move: g7g5>, <Move: g7g6>]
Let’s move our rook. To perform a move, we use Board.apply()
.
Moves can be created manually with the Move()
constructor.
selected_move = Move(D7, D3)
board.apply(selected_move)
board
Oh, but that was a blunder. Moves can be undone with Board.undo()
, which returns
the last Move
applied. Getting the str
of a Move
renders the move
in UCI long algebraic notation.
print("Undoing " + str(board.undo()))
board
Undoing d7d3
Let’s run the game through for a bit. Moves can also be constructed from UCI or standard algebraic notation.
board.apply(Move.from_san("g5", board))
board.apply(Move.from_uci("h2h4"))
board.apply(Move(G5, H4))
board.apply(Move(G3, H4))
board.apply(Move.from_san("Kg7", board))
board.apply(Move.from_san("Rg3", board))
board
Black exposed their king, and is now in check.
board in CHECK
True
But the game is still ongoing…
board in CHECKMATE or board in DRAW
False
Total running time of the script: (0 minutes 0.005 seconds)