Core API Reference
This module covers game tree representation, immutable cursors, board position analysis, and tournament draw adjudication.
Game
libscid.Game
Game(position: Position | None = None)
Chess game entity encapsulating metadata tags and hierarchical movetext.
A Game represents a complete chess contest, including the Seven Tag
Roster (STR) metadata (Event, Site, Date, Round, White, Black,
Result), supplemental PGN header tags, the initial board starting
position, and the hierarchical movetext tree (mainline moves, alternative
variations, NAG annotations, and commentary).
Game tree traversal and editing are performed by creating a
Cursor via create_cursor().
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn(
... '[Event "World Championship"]\n'
... '[White "Kasparov, Garry"]\n'
... '[Black "Karpov, Anatoly"]\n'
... '[Result "1-0"]\n\n'
... '1. e4 e5 2. Nf3 Nc6 3. Bb5 1-0'
... )
>>> game.get_tag("White")
'Kasparov, Garry'
>>> game.mainline_move_count
5
>>> cursor = game.create_cursor()
>>> cursor.next().previous_move_san
'e4'
Initialise a blank chess game.
Initialises standard default PGN tags (Event, Site, Date,
Round, White, Black, Result). If a custom starting position
is supplied, a FEN tag is automatically attached.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
position
|
Position | None
|
Optional custom starting |
None
|
Examples:
>>> import libscid
>>> game = libscid.Game()
>>> game.get_tag("Result")
'*'
>>> pos = libscid.Position.from_fen("4k3/8/8/8/8/8/8/4K2R w K - 0 1")
>>> custom_game = libscid.Game(pos)
>>> custom_game.get_tag("FEN")
'4k3/8/8/8/8/8/8/4K2R w K - 0 1'
Source code in src/libscid/_game.py
Attributes
mainline_move_count
property
Total number of halfmoves (ply) in the mainline of the game.
Methods:
from_pgn
classmethod
Create a game by parsing PGN text.
Parses PGN header tags, move notation, nested variations, comments, and Numeric Annotation Glyphs (NAGs) from the supplied string buffer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pgn
|
str | bytes
|
PGN text string or bytes to parse. |
required |
position
|
Position | None
|
Optional custom starting |
None
|
Returns:
| Type | Description |
|---|---|
Game
|
A newly allocated |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If the PGN syntax is invalid, illegal moves are encountered, or parsing fails. |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. d4 d5 2. c4 e6 *")
>>> game.mainline_move_count
4
Source code in src/libscid/_game.py
get_tag
Retrieve the value of a PGN header tag by name.
Queries Seven Tag Roster (STR) headers, well-known supplemental tags (e.g. "ECO", "FEN"), and custom tags.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | bytes
|
PGN tag header name (e.g. "White", "ECO", "Event"). |
required |
Returns:
| Type | Description |
|---|---|
str
|
The tag value string, or an empty string if the tag is absent. |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn('[White "Tal, Mikhail"] 1. e4 *')
>>> game.get_tag("White")
'Tal, Mikhail'
>>> game.get_tag("Annotator")
''
Source code in src/libscid/_game.py
set_tag
Set or update the value of a PGN header tag.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | bytes
|
PGN tag header name. |
required |
value
|
str | bytes
|
Value string to assign to the tag. |
required |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If the tag value is invalid (e.g. malformed "Result"). |
Examples:
>>> import libscid
>>> game = libscid.Game()
>>> game.set_tag("White", "Spassky, Boris")
>>> game.set_tag("WhiteElo", "2660")
>>> game.get_tag("WhiteElo")
'2660'
Source code in src/libscid/_game.py
remove_tag
Remove a supplemental PGN header tag by name.
Standard mandatory Seven Tag Roster (STR) tags and the FEN tag
cannot be removed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | bytes
|
PGN tag header name to remove. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the tag was present and successfully removed; False if the tag was not found or is non-removable. |
Examples:
>>> import libscid
>>> game = libscid.Game()
>>> game.set_tag("Annotator", "Fischer")
>>> game.remove_tag("Annotator")
True
>>> game.remove_tag("White")
False
Source code in src/libscid/_game.py
get_tags
Retrieve all PGN header tags present in the game.
Returns:
| Type | Description |
|---|---|
tuple[tuple[str, str], ...]
|
A tuple of |
Examples:
Source code in src/libscid/_game.py
create_cursor
create_cursor() -> Cursor
Create a new cursor initialised at the game's starting position.
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 *")
>>> cursor = game.create_cursor()
>>> cursor.next().previous_move_san
'e4'
Source code in src/libscid/_game.py
iter_movetext
iter_movetext(
*, variations: bool = True
) -> Iterator[MovetextEvent]
Iterate over hierarchical movetext events from the game start.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variations
|
bool
|
Whether to recursively traverse nested variation branches. Defaults to True. |
True
|
Returns:
| Type | Description |
|---|---|
Iterator[MovetextEvent]
|
An iterator yielding |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4 d5) 1... e5 *")
>>> moves = [
... e.san for e in game.iter_movetext()
... if isinstance(e, libscid.MovetextMove)
... ]
>>> moves
['e4', 'd4', 'd5', 'e5']
Source code in src/libscid/_game.py
to_pgn
to_pgn(options: PgnOptions | None = None) -> str
Serialise the game to a standard PGN-formatted string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
options
|
PgnOptions | None
|
Optional |
None
|
Returns:
| Type | Description |
|---|---|
str
|
PGN-formatted string representing the game. |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 $1 {King pawn} (1. c4) e5 *")
>>> options = libscid.PgnOptions(
... symbolic_nags=True,
... variations=False,
... )
>>> pgn = game.to_pgn(options)
>>> "1.e4 ! {King pawn} 1...e5" in pgn
True
Source code in src/libscid/_game.py
Cursor
libscid.Cursor
Navigational node within a hierarchical chess game movetext tree.
A Cursor points to a specific ply within a Game,
providing access to the board Position, incoming and
departing moves, commentary, NAG annotations, and variation branching.
Navigation methods (such as next(),
previous(), and
enter_variation()) return newly
allocated cursor instances representing target locations, maintaining
immutable value semantics during traversal. Tree mutation operations
(such as append_move() and
set_comment()) modify the underlying game.
Direct instantiation of Cursor is disallowed; instances must be obtained
via Game.create_cursor() or navigation
methods.
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 Nc6 *")
>>> cursor = game.create_cursor()
>>> cursor.is_line_start
True
>>> move1 = cursor.next()
>>> move1.previous_move_san
'e4'
>>> move1.position.side_to_move
'black'
Disallow direct cursor instantiation.
Raises:
| Type | Description |
|---|---|
TypeError
|
Always raised if instantiated directly. |
Source code in src/libscid/_cursor.py
Attributes
arbiter
property
arbiter: Arbiter
previous_move_san
property
Standard Algebraic Notation of the incoming move, or None at line start.
next_move_san
property
Standard Algebraic Notation of the upcoming move, or None at line end.
previous_move_uci
property
Universal Chess Interface notation of the incoming move, or None at start.
next_move_uci
property
Universal Chess Interface notation of the upcoming move, or None at end.
previous_move_nags
property
previous_move_nags: tuple[Nag, ...] | None
NAG annotations attached to the incoming move, or None at line start.
next_move_nags
property
next_move_nags: tuple[Nag, ...] | None
NAG annotations attached to the upcoming move, or None at line end.
comment
property
Commentary text attached to the incoming move, or None at line start.
preceding_comment
property
Introductory commentary preceding the first move, or None if not at start.
variation_count
property
Number of alternative variations branching from the upcoming move.
variation_depth
property
Variation nesting depth (0 for mainline, 1 for sub-variation, etc.).
variation_index
property
Sibling index among alternative variations at the parent fork.
is_variation_line
property
True if the cursor is positioned on a sub-variation branch.
is_line_start
property
True if the cursor is at the beginning of the current line.
is_line_end
property
True if the cursor is at the terminal end of the current line.
position
property
position: Position
Methods:
clone
clone() -> Cursor
Duplicate this cursor at its current position.
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 *")
>>> cursor = game.create_cursor().next()
>>> cloned = cursor.clone()
>>> cloned.previous_move_san
'e4'
Source code in src/libscid/_cursor.py
next
next() -> Cursor | None
Advance the cursor to the next move in the current line.
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 *")
>>> cursor = game.create_cursor()
>>> cursor.next().previous_move_san
'e4'
>>> cursor.to_game_end().next() is None
True
Source code in src/libscid/_cursor.py
previous
previous() -> Cursor | None
Step the cursor backward to the preceding move in the current line.
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 *")
>>> cursor = game.create_cursor().to_game_end()
>>> cursor.previous().previous_move_san
'e4'
>>> game.create_cursor().previous() is None
True
Source code in src/libscid/_cursor.py
to_game_start
to_game_start() -> Cursor
Move the cursor directly to the beginning of the mainline.
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 *")
>>> cursor = game.create_cursor().to_game_end()
>>> cursor.to_game_start().is_line_start
True
Source code in src/libscid/_cursor.py
to_game_end
to_game_end() -> Cursor
Move the cursor directly to the terminal position of the mainline.
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 *")
>>> cursor = game.create_cursor()
>>> cursor.to_game_end().is_line_end
True
Source code in src/libscid/_cursor.py
to_main_line_offset
to_main_line_offset(offset: int) -> Cursor | None
Move the cursor to a specific 0-based ply offset on the mainline.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset
|
int
|
Zero-based ply offset from the start of the mainline. |
required |
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 Nc6 *")
>>> cursor = game.create_cursor()
>>> ply2 = cursor.to_main_line_offset(2)
>>> ply2.previous_move_san
'e5'
>>> cursor.to_main_line_offset(10) is None
True
Source code in src/libscid/_cursor.py
enter_variation
enter_variation(index: int) -> Cursor | None
Descend into a child variation branching from the upcoming move.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
index
|
int
|
Zero-based index of the variation branch to enter. |
required |
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4 d5) 1... e5 *")
>>> cursor = game.create_cursor()
>>> var_cursor = cursor.enter_variation(0)
>>> var_cursor.next().previous_move_san
'd4'
>>> var_cursor.variation_depth
1
Source code in src/libscid/_cursor.py
exit_variation
exit_variation() -> Cursor | None
Ascend from the current variation back to its parent line.
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4 d5) 1... e5 *")
>>> var_cursor = game.create_cursor().enter_variation(0)
>>> parent = var_cursor.exit_variation()
>>> parent.variation_depth
0
Source code in src/libscid/_cursor.py
append_move
append_move(san: str | bytes) -> Cursor
Append a move in Standard Algebraic Notation to the end of the line.
The cursor must currently be located at the end of the line
(is_line_end must be True).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
san
|
str | bytes
|
Standard Algebraic Notation move string (e.g. "e4", "Nf3"). |
required |
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the cursor is not at the end of the line. |
LibScidError
|
If the move is illegal or cannot be parsed. |
Examples:
>>> import libscid
>>> game = libscid.Game()
>>> cursor = game.create_cursor()
>>> cursor = cursor.append_move("e4")
>>> cursor.previous_move_san
'e4'
>>> cursor = cursor.append_move("e5")
>>> cursor.previous_move_san
'e5'
Source code in src/libscid/_cursor.py
append_game
append_game(source_game: Any) -> Cursor
Append all moves and variations from another game onto this line.
The cursor must currently be located at the end of the line
(is_line_end must be True).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_game
|
Any
|
The |
required |
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the cursor is not at the end of the line. |
LibScidError
|
If the positions are incompatible or appending fails. |
Examples:
>>> import libscid
>>> game1 = libscid.Game.from_pgn("1. e4 e5 *")
>>> game2 = libscid.Game.from_pgn(
... "2. Nf3 Nc6 *", position=game1.end_position
... )
>>> cursor = game1.create_cursor().to_game_end()
>>> cursor = cursor.append_game(game2)
>>> game1.mainline_move_count
4
Source code in src/libscid/_cursor.py
add_variation
add_variation(
preceding_comment: str | bytes = "",
) -> Cursor | None
Add a new variation branch departing from the upcoming move.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
preceding_comment
|
str | bytes
|
Optional introductory commentary text to attach to the start of the new variation branch. |
''
|
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 *")
>>> cursor = game.create_cursor()
>>> var_cursor = cursor.add_variation("Alternative opening")
>>> var_cursor = var_cursor.append_move("d4")
>>> var_cursor.previous_move_san
'd4'
Source code in src/libscid/_cursor.py
remove_variation
remove_variation() -> Cursor | None
Delete the current variation branch from the game tree.
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4 d5) 1... e5 *")
>>> var_cursor = game.create_cursor().enter_variation(0)
>>> parent = var_cursor.remove_variation()
>>> game.create_cursor().variation_count
0
Source code in src/libscid/_cursor.py
promote_variation_to_first
promote_variation_to_first() -> Cursor | None
Promote the current variation to become the first alternative sibling.
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4) (1. c4) 1... e5 *")
>>> var2 = game.create_cursor().enter_variation(1)
>>> var2.next().previous_move_san
'c4'
>>> promoted = var2.promote_variation_to_first()
>>> game.create_cursor().enter_variation(0).next().previous_move_san
'c4'
Source code in src/libscid/_cursor.py
promote_variation_to_mainline
promote_variation_to_mainline() -> Cursor | None
Promote the current variation to become the new mainline of the game.
Swaps the current variation with the existing mainline from the branching point onward.
Returns:
| Type | Description |
|---|---|
Cursor | None
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4 d5) 1... e5 *")
>>> var = game.create_cursor().enter_variation(0)
>>> new_main = var.promote_variation_to_mainline()
>>> game.create_cursor().next().previous_move_san
'd4'
Source code in src/libscid/_cursor.py
truncate
truncate() -> Cursor
Remove all subsequent moves in the current line from this point.
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 Nc6 *")
>>> cursor = game.create_cursor().to_main_line_offset(2)
>>> cursor.previous_move_san
'e5'
>>> truncated = cursor.truncate()
>>> game.mainline_move_count
2
Source code in src/libscid/_cursor.py
truncate_before
truncate_before() -> Cursor
Remove all preceding moves in the current line up to this point.
Returns:
| Type | Description |
|---|---|
Cursor
|
A new |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 2. Nf3 Nc6 *")
>>> cursor = game.create_cursor().to_main_line_offset(2)
>>> start = cursor.truncate_before()
>>> game.mainline_move_count
2
>>> start.next().previous_move_san
'Nf3'
Source code in src/libscid/_cursor.py
iter_movetext
iter_movetext(
*, variations: bool = True
) -> Iterator[MovetextEvent]
Iterate over movetext events starting from this cursor position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variations
|
bool
|
Whether to recursively traverse variation branches. Defaults to True. |
True
|
Returns:
| Type | Description |
|---|---|
Iterator[MovetextEvent]
|
An iterator yielding |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 (1. d4 d5) 1... e5 *")
>>> moves = [
... e.san for e in game.create_cursor().iter_movetext()
... if isinstance(e, libscid.MovetextMove)
... ]
>>> moves
['e4', 'd4', 'd5', 'e5']
Source code in src/libscid/_cursor.py
set_comment
Set commentary text at the current cursor node.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comment
|
str | bytes
|
Commentary text to attach. |
required |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 *")
>>> cursor = game.create_cursor().next()
>>> cursor.set_comment("King Pawn opening")
>>> cursor.comment
'King Pawn opening'
Source code in src/libscid/_cursor.py
remove_comment
add_nag
add_nag(nag: Nag) -> bool
Attach a Numeric Annotation Glyph to the incoming move.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nag
|
Nag
|
The |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the NAG was attached successfully; otherwise False. |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 *")
>>> cursor = game.create_cursor().next()
>>> cursor.add_nag(libscid.Nag("!"))
True
>>> [nag.symbol for nag in cursor.previous_move_nags]
['!']
Source code in src/libscid/_cursor.py
remove_move_nag
Remove move evaluation NAGs ($1-$9) from the incoming move.
Returns:
| Type | Description |
|---|---|
bool
|
True if a move NAG was found and removed; otherwise False. |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 $1 $14 e5 *")
>>> cursor = game.create_cursor().next()
>>> cursor.remove_move_nag()
True
>>> [nag.text for nag in cursor.previous_move_nags]
['$14']
Source code in src/libscid/_cursor.py
remove_position_nag
Remove positional evaluation NAGs ($10-$255) from the incoming move.
Returns:
| Type | Description |
|---|---|
bool
|
True if a positional NAG was found and removed; otherwise False. |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 $1 $14 e5 *")
>>> cursor = game.create_cursor().next()
>>> cursor.remove_position_nag()
True
>>> [nag.text for nag in cursor.previous_move_nags]
['$1']
Source code in src/libscid/_cursor.py
remove_nags
Remove all Numeric Annotation Glyphs from the incoming move.
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 $1 $14 e5 *")
>>> cursor = game.create_cursor().next()
>>> cursor.remove_nags()
>>> cursor.previous_move_nags
()
Source code in src/libscid/_cursor.py
Position
libscid.Position
Represents a chess board state and rule validation context.
Encapsulates piece placement across all 64 squares, active side to move, castling availability rights, en passant target square, halfmove clock (fifty-move rule), and fullmove counter. Provides methods to query legal moves, evaluate check, checkmate, and stalemate states, calculate move metadata flags, and execute moves in-place.
Examples:
>>> import libscid
>>> fen = (
... "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
... )
>>> pos = libscid.Position.from_fen(fen)
>>> pos.side_to_move
'black'
>>> pos.is_check
False
>>> pos.get_piece_at("e4")
'P'
>>> pos.apply_san("e5")
>>> pos.side_to_move
'white'
Disallows direct construction.
Raises:
| Type | Description |
|---|---|
TypeError
|
Position objects cannot be instantiated directly and must be obtained via factory classmethods or domain handles. |
Source code in src/libscid/_position.py
Attributes
fen
property
Full 6-field Forsyth–Edwards Notation (FEN) string of the board state.
Returns:
| Type | Description |
|---|---|
str
|
The complete FEN string including piece placement, side to move, castling availability, en passant target square, halfmove clock, and fullmove number. |
Examples:
side_to_move
property
The active player colour whose turn it is to move.
Returns:
| Type | Description |
|---|---|
Literal['white', 'black']
|
|
Examples:
fullmove_number
property
The 1-based fullmove counter.
Starts at 1 and increments after each move made by Black.
Returns:
| Type | Description |
|---|---|
int
|
The positive integer fullmove number. |
Examples:
halfmove_clock
property
The halfmove clock (ply count) for the fifty-move draw rule.
Counts the number of halfmoves since the last pawn advance or piece capture.
Returns:
| Type | Description |
|---|---|
int
|
The non-negative integer halfmove clock. |
Examples:
is_check
property
is_checkmate
property
Whether the position is in checkmate.
A position is checkmate when the active player's king is in check and has no legal moves.
Returns:
| Type | Description |
|---|---|
bool
|
|
Examples:
is_stalemate
property
Whether the position is in stalemate.
A position is stalemate when the active player is not in check and has no legal moves available.
Returns:
| Type | Description |
|---|---|
bool
|
|
Examples:
legal_moves
property
All strictly legal moves available in the current position.
Returns:
| Type | Description |
|---|---|
tuple[str, ...]
|
Tuple of legal moves formatted as coordinate UCI strings
(e.g. |
Examples:
Methods:
from_fen
classmethod
from_fen(fen: str | bytes) -> Position
Creates a new board position initialised from a FEN string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fen
|
str | bytes
|
Forsyth–Edwards Notation (FEN) string or UTF-8 encoded bytes. |
required |
Returns:
| Type | Description |
|---|---|
Position
|
A new |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
... )
>>> pos.side_to_move
'black'
>>> pos.get_piece_at("e4")
'P'
Source code in src/libscid/_position.py
get_piece_at
Retrieves the piece residing on a specified board square.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
square
|
str | bytes
|
Algebraic coordinate string or UTF-8 bytes (e.g. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
Single-character piece letter ( |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
... )
>>> pos.get_piece_at("e1")
'K'
>>> pos.get_piece_at("e8")
'k'
>>> pos.get_piece_at("e4") is None
True
Source code in src/libscid/_position.py
get_move_metadata
get_move_metadata(move: str | bytes) -> MoveMetadata
Calculates structural and rule characteristics for a move.
Evaluates check, checkmate, castling, and pawn promotion properties for the given move text against the current position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
move
|
str | bytes
|
Standard Algebraic Notation (SAN) or coordinate UCI move string
or bytes (e.g. |
required |
Returns:
| Type | Description |
|---|---|
MoveMetadata
|
A |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "r1bqkb1r/pppp1ppp/2n5/4p3/2B1n3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 5"
... )
>>> flags = pos.get_move_metadata("O-O")
>>> bool(flags & libscid.MoveMetadata.CASTLING)
True
>>> mate_pos = libscid.Position.from_fen(
... "r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR"
... " w KQkq - 4 4"
... )
>>> mate_flags = mate_pos.get_move_metadata("Qxf7#")
>>> bool(mate_flags & libscid.MoveMetadata.CHECKMATE)
True
Source code in src/libscid/_position.py
to_san
Converts and normalises a move string to canonical SAN against this position.
Does not mutate the board state. Accepts standard SAN, permissive move notations, or coordinate UCI strings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
move
|
str | bytes
|
Move notation string or bytes to normalise (e.g. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Canonical Standard Algebraic Notation string (e.g. |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
... )
>>> pos.to_san("e2e4")
'e4'
>>> pos.to_san("g1f3")
'Nf3'
Source code in src/libscid/_position.py
apply_san
Applies a Standard Algebraic Notation (SAN) move in-place to this position.
Updates piece positions, active colour, castling rights, en passant state, halfmove clock, and fullmove number.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
san
|
str | bytes
|
Standard Algebraic Notation move string or bytes (e.g. |
required |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
... )
>>> pos.apply_san("e4")
>>> pos.get_piece_at("e4")
'P'
>>> pos.side_to_move
'black'
Source code in src/libscid/_position.py
apply_uci
Applies a coordinate UCI move in-place to this position.
Updates piece positions, active colour, castling rights, en passant state, halfmove clock, and fullmove number.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
uci
|
str | bytes
|
Coordinate UCI move string or bytes (e.g. |
required |
Raises:
| Type | Description |
|---|---|
LibScidError
|
If |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
... )
>>> pos.apply_uci("e2e4")
>>> pos.get_piece_at("e4")
'P'
>>> pos.side_to_move
'black'
Source code in src/libscid/_position.py
Arbiter
libscid.Arbiter
Arbiter(cursor: Cursor)
Evaluates tournament rules and draw claim conditions for a cursor position.
An Arbiter instance is typically accessed via the
Cursor.arbiter property. It evaluates claimable
draw conditions defined by the FIDE Laws of Chess at the cursor's current
position, including the fifty-move rule and threefold repetition.
Examples:
>>> import libscid
>>> pgn = "1. Nf3 Nf6 2. Ng1 Ng8 3. Nf3 Nf6 4. Ng1 Ng8 *"
>>> cursor = libscid.Game.from_pgn(pgn).create_cursor().to_game_end()
>>> cursor.arbiter.can_claim_threefold_repetition
True
>>> cursor.arbiter.can_claim_fifty_move_rule
False
Initialise an arbiter bound to a specific cursor position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cursor
|
Cursor
|
The cursor navigating the game tree to inspect. |
required |
Examples:
>>> import libscid
>>> game = libscid.Game.from_pgn("1. e4 e5 *")
>>> cursor = game.create_cursor().to_game_end()
>>> arbiter = cursor.arbiter
>>> arbiter.can_claim_fifty_move_rule
False
Source code in src/libscid/_arbiter.py
Attributes
can_claim_fifty_move_rule
property
Check whether a draw can be claimed under the fifty-move rule.
According to the FIDE Laws of Chess, a player may claim a draw if the last 50 consecutive full moves (100 halfmoves / ply) have been completed by each player without any piece capture and without any pawn advance.
Returns:
| Type | Description |
|---|---|
bool
|
True if the halfmove clock is at least 100; otherwise False. |
Examples:
>>> import libscid
>>> pos = libscid.Position.from_fen(
... "8/8/8/8/8/4k3/8/4K3 w - - 100 51"
... )
>>> game = libscid.Game(position=pos)
>>> game.create_cursor().arbiter.can_claim_fifty_move_rule
True
>>> normal_game = libscid.Game.from_pgn("1. e4 e5 *")
>>> normal_game.create_cursor().arbiter.can_claim_fifty_move_rule
False
can_claim_threefold_repetition
property
Check whether a draw can be claimed under the threefold repetition rule.
According to the FIDE Laws of Chess, a player may claim a draw if the exact same board position has occurred at least three times along the path from the game start to this cursor node. Two positions are identical if the side to move, piece placements, castling rights, and en passant target squares are identical.
Returns:
| Type | Description |
|---|---|
bool
|
True if the current board state has occurred 3 or more times along the line of play; otherwise False. |
Examples:
>>> import libscid
>>> pgn = "1. Nf3 Nf6 2. Ng1 Ng8 3. Nf3 Nf6 4. Ng1 Ng8 *"
>>> cursor = libscid.Game.from_pgn(pgn).create_cursor().to_game_end()
>>> cursor.arbiter.can_claim_threefold_repetition
True
>>> non_rep = libscid.Game.from_pgn("1. e4 e5 2. Nf3 Nc6 *")
>>> non_rep.create_cursor().arbiter.can_claim_threefold_repetition
False