chmengine

A silly chess engine that picks moves using heatmaps

class chmengine.CMHMEngine(board: Optional[Board] = None, depth: int = 1)

Bases: object

A silly chess engine that picks moves using heatmaps.

This class manages a chess board and evaluates moves by using recursion-based heatmaps.

property board: Board

Get the current chess board.

Returns:
chess.Board

The current board state.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.board
Board('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1')
board_copy_pushed(move: Move, board: Optional[Board] = None) Board

Return a copy of the board with the given move applied.

Parameters:
movechess.Move

The move to push onto the board.

boardOptional[chess.Board], optional

The board to copy; if None, uses the engine’s current board.

Returns:
chess.Board

A new board instance with the move applied.

Examples

>>> from chmengine import CMHMEngine
>>> from chess import Move
>>> engine = CMHMEngine()
>>> new_board = engine.board_copy_pushed(Move.from_uci('e2e4'))
>>> new_board
Board('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1')
current_moves_list(board: Optional[Board] = None) List[Move]

Retrieve the list of legal moves for the current board position.

Parameters:
boardOptional[chess.Board], default: None

The board for which to get legal moves. If None, the engine’s current board is used.

Returns:
List[chess.Move]

A list of legal moves available on the board.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> moves = engine.current_moves_list()
>>> moves[15]
Move.from_uci('e2e4')
current_picks_list(board: Optional[Board] = None) List[Pick]

Retrieve the list of legal null-scored picks for the current board position.

Parameters:
boardOptional[chess.Board], default: None

The board for which to get legal moves. If None, the engine’s current board is used.

Returns:
List[Pick]

A list of null-scored picks available on the board.

current_player_heatmap_index(board: Optional[Board] = None) int

Get the heatmap index corresponding to the active (current) player.

Parameters:
boardOptional[chess.Board]
Returns:
int

The index for the current player. Typically, if the current turn is White (index 0), this returns 0, and vice versa.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.current_player_heatmap_index()
0
property depth: int

Get the current recursion depth setting.

Returns:
int

The current recursion depth used for heatmap calculations.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.depth
1
fen(board: Optional[Board] = None) str

Obtain the FEN string for a given board state. If no board is provided, the engine’s current board is used.

Parameters:
boardOptional[Board]

The board for which to retrieve the FEN string.

Returns:
str

The FEN string representing the board state.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.fen()
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
get_king_boxes(board: Optional[Board] = None) Tuple[List[int], List[int]]

Compute the bounding boxes for the kings on the board.

For both the current and opponent kings, this method calculates a “box” (a list of square indices) representing the king’s immediate surroundings.

Parameters:
boardOptional[chess.Board], default: None

The board to use; if None, the engine’s current board is used.

Returns:
Tuple[List[int], List[int]]

A tuple containing two lists: the first is the box for the current king, and the second is the box for the opponent king.

get_or_calc_move_maps(depth: Optional[int] = None) Dict[Move, GradientHeatmap]

Compute or retrieve precomputed heatmaps for all legal moves from the current board.

For each legal move from the current board, this method generates a corresponding heatmap by applying the move and evaluating the resulting position with a given recursion depth.

Parameters:
depthOptional[int], default: None

The recursion depth for the heatmap calculation. If None, the engine’s current depth is used.

Returns:
Dict[Move, GradientHeatmap]

A dictionary mapping each legal move to its corresponding heatmap.

Raises:
ValueError

If the current board has no legal moves.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> move_maps = engine.get_or_calc_move_maps()
>>> some_move = list(move_maps.keys())[0]
>>> type(move_maps[some_move])
<class 'heatmaps.ChessMoveHeatmap'>
get_or_calc_move_maps_list() List[Tuple[Move, GradientHeatmap]]

Retrieve a list of move-to-heatmap mappings.

This method converts the dictionary returned by get_or_calc_move_maps() into a list of tuples for easier iteration, where each tuple contains a move and its corresponding heatmap.

Returns:
List[Tuple[Move, GradientHeatmap]]

A list of (move, heatmap) tuples.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> first_move = engine.get_or_calc_move_maps_list()[0][0]
>>> first_move
Move.from_uci('g1h3')
static heatmap_data_is_zeros(heatmap: GradientHeatmap) bool

Check if the heatmap data is entirely zero.

Parameters:
heatmapheatmaps.GradientHeatmap

The heatmap object to check.

Returns:
bool

True if all values in the heatmap data are zero; otherwise, False.

Examples

>>> from chmengine import CMHMEngine
>>> from heatmaps import GradientHeatmap
>>> hmap = GradientHeatmap()
>>> CMHMEngine.heatmap_data_is_zeros(hmap)
True
>>> hmap[32][1] = 1.0
>>> CMHMEngine.heatmap_data_is_zeros(hmap)
False
other_player_heatmap_index(board: Optional[Board] = None) int

Get the heatmap index corresponding to the inactive (other) player.

Returns:
int

The index for the other player. Typically, if the current turn is White (index 0), this returns 1, and vice versa.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.other_player_heatmap_index()
1
pick_move(pick_by: str = 'all-delta', board: Optional[Board] = None) Pick

Select a move based on various heatmap-derived criteria.

The method evaluates candidate moves using multiple heuristics (such as delta, maximum, minimum, king attack/defense, etc.) and returns one move chosen at random from the set of the best candidate moves according to the specified criteria.

The evaluation score is provided from the perspective of the player making the move:

a positive score indicates a move that is considered beneficial for the mover, while a negative score indicates a move that is considered detrimental.

This scoring convention is different from many traditional chess engines, where scores are often expressed as positive for White advatage and negative for Black.

Parameters:
pick_bystr, default: “all-delta”

A string indicating the selection heuristic. Supported options include “all-delta”, “all-max”, “all-min”, “king-atk”, “king-def”, and “king-delta”.

boardchess.Board, default: None

Used by child classes; pick_move method

Returns:
Pick

A tuple-like containing the chosen move and its associated evaluation score, where the score is from the perspective of the player making the move (i.e., positive values indicate favorable outcomes for that player, and negative values indicate unfavorable outcomes).

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> pick = picked_move, eval_score = engine.pick_move()
>>> pick
Pick(move=e2e4, score=10.0)
>>> picked_move
Move.from_uci('e2e4')
>>> # A positive score indicates a move leading to a good position for the mover,
>>> # whereas a negative score indicates a leading to a bad position.
>>> eval_score
10.0
static update_target_moves_by_delta(target_moves_by_delta: List[Union[Tuple[None, None], Pick]], current_player_sum: float64, other_player_sum: float64, move: Move) List[Pick]

Update the candidate moves based on the delta between current and other player’s sums.

The delta is computed as the difference between the current player’s sum and the other player’s sum. If the calculated delta is greater than the current best, the candidate list is replaced; if equal, the move is appended.

Parameters:
target_moves_by_deltaList[Union[Tuple[None, None], Pick]]

The current list of candidate moves and their delta scores.

current_player_sumnumpy.float64

The sum of move intensities for the current player.

other_player_sumnumpy.float64

The sum of move intensities for the other player.

movechess.Move

The move being evaluated.

Returns:
List[Pick]

The updated list of candidate moves with their delta scores.

static update_target_moves_by_king_delta(target_moves_by_king_delta: List[Union[Tuple[None, None], Pick]], move: Move, current_king_min: float64, other_king_sum: float64) List[Pick]

Update candidate moves based on the king’s delta value.

Calculates the delta between the opponent’s king intensity and the current king’s minimum intensity, updating the candidate list if this delta is greater than the current best.

Parameters:
target_moves_by_king_deltaList[Union[Tuple[None, None], Pick]]

The current candidate moves for the king delta criterion.

movechess.Move

The move being evaluated.

current_king_minnumpy.float64

The minimum intensity value for the current king.

other_king_sumnumpy.float64

The total intensity value for the opponent’s king.

Returns:
List[Pick]

The updated list of candidate moves based on king delta.

static update_target_moves_by_max_current(target_moves_by_max_current: List[Union[Tuple[None, None], Pick]], transposed_map: ndarray, move: Move, color_index: int) Tuple[float64, List[Pick]]

Update the candidate moves for maximizing the current player’s intensity.

Computes the current player’s total intensity from the transposed heatmap and updates the candidate list if the new sum is greater than the current best.

Parameters:
target_moves_by_max_currentList[Union[Tuple[None, None], Pick]]

The current candidate moves for maximizing the current player’s intensity.

transposed_mapnumpy.ndarray

The transposed heatmap data array.

movechess.Move

The move being evaluated.

color_indexint

The index corresponding to the current player.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the current player’s sum and the updated candidate list.

static update_target_moves_by_max_other_king(target_moves_by_max_other_king: List[Union[Tuple[None, None], Pick]], heatmap: GradientHeatmap, move: Move, color_index: int, other_king_box: List[int]) Tuple[float64, List[Pick]]

Update candidate moves for maximizing the opponent king’s intensity.

Calculates the opponent king’s total intensity from the heatmap over the specified area and updates the candidate list if a higher intensity sum is found.

Parameters:
target_moves_by_max_other_kingList[Union[Tuple[None, None], Pick]]

The candidate moves list for maximizing opponent king’s intensity.

heatmapheatmaps.GradientHeatmap

The heatmap object containing move intensities.

movechess.Move

The move being evaluated.

color_indexint

The index corresponding to the opponent.

other_king_boxList[int]

A list of board squares representing the area around the opponent’s king.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the opponent king’s sum and the updated candidate list.

static update_target_moves_by_min_current_king(target_moves_by_min_current_king: List[Union[Tuple[None, None], Pick]], heatmap: GradientHeatmap, move: Move, other_index: int, current_king_box: List[int]) Tuple[float64, List[Pick]]

Update candidate moves for minimizing the current king’s intensity.

Extracts the intensity values for the current king from the heatmap and updates the candidate list if a lower intensity sum is found.

Parameters:
target_moves_by_min_current_kingList[Union[Tuple[None, None], Pick]]

The candidate moves list for minimizing current king’s intensity.

heatmapheatmaps.GradientHeatmap

The heatmap object containing move intensities.

movechess.Move

The move being evaluated.

other_indexint

The index corresponding to the opponent.

current_king_boxList[int]

A list of board squares representing the area around the current king.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the current king’s sum and the updated candidate list.

static update_target_moves_by_min_other(target_moves_by_min_other: List[Union[Tuple[None, None], Pick]], transposed_map: ndarray, move: Move, other_index: int) Tuple[float64, List[Pick]]

Update the candidate moves for minimizing the opponent’s sum.

Calculates the opponent’s total move intensity from the transposed heatmap, and updates the candidate list if the new sum is lower than the current best.

Parameters:
target_moves_by_min_otherList[Union[Tuple[None, None], Pick]]

The current candidate moves for minimizing the opponent’s intensity.

transposed_mapnumpy.ndarray

The transposed heatmap data array.

movechess.Move

The move being evaluated.

other_indexint

The index corresponding to the opponent.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the opponent’s sum and the updated candidate list.

class chmengine.CMHMEngine2(board: Optional[Board] = None, depth: int = 1)

Bases: CMHMEngine, Quartney

Cmhmey Jr., the love-child of CMHMEngine and Quartney

property board: Board

Get the current chess board.

Returns:
chess.Board

The current board state.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.board
Board('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1')
board_copy_pushed(move: Move, board: Optional[Board] = None) Board

Return a copy of the board with the given move applied.

Parameters:
movechess.Move

The move to push onto the board.

boardOptional[chess.Board], optional

The board to copy; if None, uses the engine’s current board.

Returns:
chess.Board

A new board instance with the move applied.

Examples

>>> from chmengine import CMHMEngine
>>> from chess import Move
>>> engine = CMHMEngine()
>>> new_board = engine.board_copy_pushed(Move.from_uci('e2e4'))
>>> new_board
Board('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1')
cache_dir: str = '.\\SQLite3Caches\\QTables'
current_moves_list(board: Optional[Board] = None) List[Move]

Retrieve the list of legal moves for the current board position.

Parameters:
boardOptional[chess.Board], default: None

The board for which to get legal moves. If None, the engine’s current board is used.

Returns:
List[chess.Move]

A list of legal moves available on the board.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> moves = engine.current_moves_list()
>>> moves[15]
Move.from_uci('e2e4')
current_picks_list(board: Optional[Board] = None) List[Pick]

Retrieve the list of legal null-scored picks for the current board position.

Parameters:
boardOptional[chess.Board], default: None

The board for which to get legal moves. If None, the engine’s current board is used.

Returns:
List[Pick]

A list of null-scored picks available on the board.

current_player_heatmap_index(board: Optional[Board] = None) int

Get the heatmap index corresponding to the active (current) player.

Parameters:
boardOptional[chess.Board]
Returns:
int

The index for the current player. Typically, if the current turn is White (index 0), this returns 0, and vice versa.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.current_player_heatmap_index()
0
property depth: int

Get the current recursion depth setting.

Returns:
int

The current recursion depth used for heatmap calculations.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.depth
1
fen(board: Optional[Board] = None) str

Obtain the FEN string for a given board state. If no board is provided, the engine’s current board is used.

Parameters:
boardOptional[Board]

The board for which to retrieve the FEN string.

Returns:
str

The FEN string representing the board state.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.fen()
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
get_king_boxes(board: Optional[Board] = None) Tuple[List[int], List[int]]

Compute the bounding boxes for the kings on the board.

For both the current and opponent kings, this method calculates a “box” (a list of square indices) representing the king’s immediate surroundings.

Parameters:
boardOptional[chess.Board], default: None

The board to use; if None, the engine’s current board is used.

Returns:
Tuple[List[int], List[int]]

A tuple containing two lists: the first is the box for the current king, and the second is the box for the opponent king.

get_or_calc_move_maps(depth: Optional[int] = None) Dict[Move, GradientHeatmap]

Compute or retrieve precomputed heatmaps for all legal moves from the current board.

For each legal move from the current board, this method generates a corresponding heatmap by applying the move and evaluating the resulting position with a given recursion depth.

Parameters:
depthOptional[int], default: None

The recursion depth for the heatmap calculation. If None, the engine’s current depth is used.

Returns:
Dict[Move, GradientHeatmap]

A dictionary mapping each legal move to its corresponding heatmap.

Raises:
ValueError

If the current board has no legal moves.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> move_maps = engine.get_or_calc_move_maps()
>>> some_move = list(move_maps.keys())[0]
>>> type(move_maps[some_move])
<class 'heatmaps.ChessMoveHeatmap'>
get_or_calc_move_maps_list() List[Tuple[Move, GradientHeatmap]]

Retrieve a list of move-to-heatmap mappings.

This method converts the dictionary returned by get_or_calc_move_maps() into a list of tuples for easier iteration, where each tuple contains a move and its corresponding heatmap.

Returns:
List[Tuple[Move, GradientHeatmap]]

A list of (move, heatmap) tuples.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> first_move = engine.get_or_calc_move_maps_list()[0][0]
>>> first_move
Move.from_uci('g1h3')
get_q_value(fen: Optional[str] = None, board: Optional[Board] = None, pieces_count: Optional[int] = None) Optional[float64]

Retrieve a cached Q‑value for a position, or None if uncached.

Parameters:
fenstr, optional

FEN of the position (deprecated; use board).

boardchess.Board, optional

Board object for filename lookup.

pieces_countint, optional

Override piece count for selecting DB file.

Returns:
float64 or None

Stored Q‑value, or None if no entry exists.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> q = engine.get_q_value()
static heatmap_data_is_zeros(heatmap: GradientHeatmap) bool

Check if the heatmap data is entirely zero.

Parameters:
heatmapheatmaps.GradientHeatmap

The heatmap object to check.

Returns:
bool

True if all values in the heatmap data are zero; otherwise, False.

Examples

>>> from chmengine import CMHMEngine
>>> from heatmaps import GradientHeatmap
>>> hmap = GradientHeatmap()
>>> CMHMEngine.heatmap_data_is_zeros(hmap)
True
>>> hmap[32][1] = 1.0
>>> CMHMEngine.heatmap_data_is_zeros(hmap)
False
other_player_heatmap_index(board: Optional[Board] = None) int

Get the heatmap index corresponding to the inactive (other) player.

Returns:
int

The index for the other player. Typically, if the current turn is White (index 0), this returns 1, and vice versa.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.other_player_heatmap_index()
1
pick_move(*args, board: Optional[Board] = None, debug: bool = False, **kwargs) Pick

Select a Pick based on heatmap evaluations and Q-table integration.

This overridden method combines heatmap evaluations with Q-value updates. It evaluates all legal moves by calculating their scores from the perspective of the current player (with positive scores indicating favorable moves and negative scores indicating unfavorable moves). The evaluation score is always from the mover’s perspective. The method then picks one move at random from the top-scoring moves, updates the Q-value for that move, and returns the selected move along with its score.

Parameters:
boardOptional[chess.Board], default: None

Pick from a given board instead of intstance board

debugbool, default: False

Allows for a print call showing the current evals of each move choice during anaylsis.

Returns:
Pick

An unpackable tuple-like containing the chosen move and its associated evaluation score. The evaluation score is expressed from the perspective of the player making the move—positive values indicate favorable outcomes and negative values indicate unfavorable outcomes.

Raises:
ValueError

If Current Board has no legal moves.

Examples

>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> move, score = engine.pick_move()
pieces_count(board: Optional[Board] = None) int

Return the number of pieces on the board in O(1) time.

This uses Board.occupied.bit_count() when given a board.

Parameters:
boardchess.Board, optional

Board whose pieces to count. Preferred parameter.

Returns:
int

Total number of pieces on the board.

Examples

>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.pieces_count()
32
qdb_path(board: Optional[Board] = None, pieces_count: Optional[Union[int, str]] = None) str

Get the full path to the Q‑table database file.

Parameters:
boardchess.Board, optional

Board object for file naming.

pieces_countint or str, optional

Explicit piece count override.

Returns:
str

Relative path: <cache_dir>/<qtable_filename(…)>

Examples

>>> import os
>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.qdb_path() == os.path.join(engine.cache_dir, engine.qtable_filename())
True
qtable_filename(board: Optional[Board] = None, pieces_count: Optional[Union[int, str]] = None) str

Build the Q‑table filename based on depth and piece count.

Parameters:
boardchess.Board, optional

Board object to derive FEN (and piece count) if fen is not given.

pieces_countint or str, optional

Explicit piece count to use. If provided, skips recomputing from board/FEN.

Returns:
str

File name of the form “qtable_depth_{depth}_piece_count_{pieces_count}.db”.

Examples

>>> import os
>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.qtable_filename() in os.listdir(path=engine.cache_dir)
True
set_q_value(value: float, fen: Optional[str] = None, board: Optional[Board] = None, pieces_count: Optional[int] = None) None

Insert or update the Q‑value for a given position in the DB.

Parameters:
valuefloat

Q‑value to store.

fenstr, optional

Position FEN (deprecated; prefer board).

boardchess.Board, optional

Board object for filename lookup.

pieces_countint, optional

Override piece count for selecting DB file.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.set_q_value(0.0, '1k6/8/8/8/8/3K4/8/8 w - - 0 1')
update_q_values(debug: bool = False) None

Back-propagate game outcome through the Q-table.

Pops all moves from the current board history and adjusts each stored Q-value in the database based on the final result (win/lose/draw).

Parameters:
debugbool, default=False

If True, print diagnostics for each back-step.

Notes

Updates the SQLite Q-table entries for every move in the game.

Examples

>>> from io import StringIO
>>> from chess import pgn
>>> from chmengine import CMHMEngine2
>>> pgn_buffer = StringIO(
...    '''
...    1. f3 e5 2. g4 Qh4# 0-1
...
...
...    '''
... )
>>> game = pgn.read_game(pgn_buffer)
>>> board = game.board()
>>> for move in game.mainline_moves():
...     board.push(move)
>>> engine = CMHMEngine2(board=board)
>>> engine.fen()
'rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3'
>>> engine.update_q_values()
>>> engine.fen()
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
static update_target_moves_by_delta(target_moves_by_delta: List[Union[Tuple[None, None], Pick]], current_player_sum: float64, other_player_sum: float64, move: Move) List[Pick]

Update the candidate moves based on the delta between current and other player’s sums.

The delta is computed as the difference between the current player’s sum and the other player’s sum. If the calculated delta is greater than the current best, the candidate list is replaced; if equal, the move is appended.

Parameters:
target_moves_by_deltaList[Union[Tuple[None, None], Pick]]

The current list of candidate moves and their delta scores.

current_player_sumnumpy.float64

The sum of move intensities for the current player.

other_player_sumnumpy.float64

The sum of move intensities for the other player.

movechess.Move

The move being evaluated.

Returns:
List[Pick]

The updated list of candidate moves with their delta scores.

static update_target_moves_by_king_delta(target_moves_by_king_delta: List[Union[Tuple[None, None], Pick]], move: Move, current_king_min: float64, other_king_sum: float64) List[Pick]

Update candidate moves based on the king’s delta value.

Calculates the delta between the opponent’s king intensity and the current king’s minimum intensity, updating the candidate list if this delta is greater than the current best.

Parameters:
target_moves_by_king_deltaList[Union[Tuple[None, None], Pick]]

The current candidate moves for the king delta criterion.

movechess.Move

The move being evaluated.

current_king_minnumpy.float64

The minimum intensity value for the current king.

other_king_sumnumpy.float64

The total intensity value for the opponent’s king.

Returns:
List[Pick]

The updated list of candidate moves based on king delta.

static update_target_moves_by_max_current(target_moves_by_max_current: List[Union[Tuple[None, None], Pick]], transposed_map: ndarray, move: Move, color_index: int) Tuple[float64, List[Pick]]

Update the candidate moves for maximizing the current player’s intensity.

Computes the current player’s total intensity from the transposed heatmap and updates the candidate list if the new sum is greater than the current best.

Parameters:
target_moves_by_max_currentList[Union[Tuple[None, None], Pick]]

The current candidate moves for maximizing the current player’s intensity.

transposed_mapnumpy.ndarray

The transposed heatmap data array.

movechess.Move

The move being evaluated.

color_indexint

The index corresponding to the current player.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the current player’s sum and the updated candidate list.

static update_target_moves_by_max_other_king(target_moves_by_max_other_king: List[Union[Tuple[None, None], Pick]], heatmap: GradientHeatmap, move: Move, color_index: int, other_king_box: List[int]) Tuple[float64, List[Pick]]

Update candidate moves for maximizing the opponent king’s intensity.

Calculates the opponent king’s total intensity from the heatmap over the specified area and updates the candidate list if a higher intensity sum is found.

Parameters:
target_moves_by_max_other_kingList[Union[Tuple[None, None], Pick]]

The candidate moves list for maximizing opponent king’s intensity.

heatmapheatmaps.GradientHeatmap

The heatmap object containing move intensities.

movechess.Move

The move being evaluated.

color_indexint

The index corresponding to the opponent.

other_king_boxList[int]

A list of board squares representing the area around the opponent’s king.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the opponent king’s sum and the updated candidate list.

static update_target_moves_by_min_current_king(target_moves_by_min_current_king: List[Union[Tuple[None, None], Pick]], heatmap: GradientHeatmap, move: Move, other_index: int, current_king_box: List[int]) Tuple[float64, List[Pick]]

Update candidate moves for minimizing the current king’s intensity.

Extracts the intensity values for the current king from the heatmap and updates the candidate list if a lower intensity sum is found.

Parameters:
target_moves_by_min_current_kingList[Union[Tuple[None, None], Pick]]

The candidate moves list for minimizing current king’s intensity.

heatmapheatmaps.GradientHeatmap

The heatmap object containing move intensities.

movechess.Move

The move being evaluated.

other_indexint

The index corresponding to the opponent.

current_king_boxList[int]

A list of board squares representing the area around the current king.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the current king’s sum and the updated candidate list.

static update_target_moves_by_min_other(target_moves_by_min_other: List[Union[Tuple[None, None], Pick]], transposed_map: ndarray, move: Move, other_index: int) Tuple[float64, List[Pick]]

Update the candidate moves for minimizing the opponent’s sum.

Calculates the opponent’s total move intensity from the transposed heatmap, and updates the candidate list if the new sum is lower than the current best.

Parameters:
target_moves_by_min_otherList[Union[Tuple[None, None], Pick]]

The current candidate moves for minimizing the opponent’s intensity.

transposed_mapnumpy.ndarray

The transposed heatmap data array.

movechess.Move

The move being evaluated.

other_indexint

The index corresponding to the opponent.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the opponent’s sum and the updated candidate list.

class chmengine.CMHMEngine2PoolExecutor(board: Optional[Board] = None, depth: int = 1, max_workers: Optional[int] = None, time_limit: Optional[float64] = None)

Bases: object

cache_dir: str = '.\\SQLite3Caches\\QTables'
engine: CMHMEngine2
executor: ProcessPoolExecutor
pick_move(debug: bool = False) Pick

Select the best move using conditional multithreaded evaluations.

Parameters:
debugbool, default: False

If True, prints debug information about the evaluations.

Returns:
Pick

The best move and its associated evaluation score.

push(move: Move) None

Helper method to update the internal board state with a pushed move.

Parameters:
moveMove
shutdown() None

Shut down the ProcessPoolExecutor.

class chmengine.CMHMEngine3(board: Optional[Board] = None, depth: int = 1, time_limit: float64 = inf, overhead: float64 = 0.0)

Bases: CMHMEngine2

A time-limited, single-process chess engine that extends CMHMEngine2 with per-move caching and iterative deepening on the current best move.

Warning

  • The default time_limit is positive infinity—by default the engine will search

    until you manually stop it.

  • Even if you interrupt the process (for example via KeyboardInterrupt) before

    pick_move returns, all the Q-table updates performed up to that point remain committed. That ongoing learning can improve future lookups.

  • To avoid unbounded CPU use, supply an explicit finite time_limit either when

    constructing the engine or in each pick_move call.

Notes

  • Builds a snapshot for each legal root move and attaches a Pick(move, score)

    seeded from the Q-table or static eval.

  • Iteratively deepens along the current best move’s branch until the time_limit

    expires, restarting from root whenever a different move becomes best.

  • Backs up improved scores into the Q-table after each deeper evaluation.

property board: Board

Get the current chess board.

Returns:
chess.Board

The current board state.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.board
Board('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1')
board_copy_pushed(move: Move, board: Optional[Board] = None) Board

Return a copy of the board with the given move applied.

Parameters:
movechess.Move

The move to push onto the board.

boardOptional[chess.Board], optional

The board to copy; if None, uses the engine’s current board.

Returns:
chess.Board

A new board instance with the move applied.

Examples

>>> from chmengine import CMHMEngine
>>> from chess import Move
>>> engine = CMHMEngine()
>>> new_board = engine.board_copy_pushed(Move.from_uci('e2e4'))
>>> new_board
Board('rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1')
cache_dir: str = '.\\SQLite3Caches\\QTables'
current_moves_list(board: Optional[Board] = None) List[Move]

Retrieve the list of legal moves for the current board position.

Parameters:
boardOptional[chess.Board], default: None

The board for which to get legal moves. If None, the engine’s current board is used.

Returns:
List[chess.Move]

A list of legal moves available on the board.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> moves = engine.current_moves_list()
>>> moves[15]
Move.from_uci('e2e4')
current_picks_list(board: Optional[Board] = None) List[Pick]

Retrieve the list of legal null-scored picks for the current board position.

Parameters:
boardOptional[chess.Board], default: None

The board for which to get legal moves. If None, the engine’s current board is used.

Returns:
List[Pick]

A list of null-scored picks available on the board.

current_player_heatmap_index(board: Optional[Board] = None) int

Get the heatmap index corresponding to the active (current) player.

Parameters:
boardOptional[chess.Board]
Returns:
int

The index for the current player. Typically, if the current turn is White (index 0), this returns 0, and vice versa.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.current_player_heatmap_index()
0
property depth: int

Get the current recursion depth setting.

Returns:
int

The current recursion depth used for heatmap calculations.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.depth
1
fen(board: Optional[Board] = None) str

Obtain the FEN string for a given board state. If no board is provided, the engine’s current board is used.

Parameters:
boardOptional[Board]

The board for which to retrieve the FEN string.

Returns:
str

The FEN string representing the board state.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.fen()
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
get_king_boxes(board: Optional[Board] = None) Tuple[List[int], List[int]]

Compute the bounding boxes for the kings on the board.

For both the current and opponent kings, this method calculates a “box” (a list of square indices) representing the king’s immediate surroundings.

Parameters:
boardOptional[chess.Board], default: None

The board to use; if None, the engine’s current board is used.

Returns:
Tuple[List[int], List[int]]

A tuple containing two lists: the first is the box for the current king, and the second is the box for the opponent king.

get_or_calc_deeper_score(board: Board) float64
Parameters:
boardBoard
Returns:
float64
get_or_calc_move_maps(depth: Optional[int] = None) Dict[Move, GradientHeatmap]

Compute or retrieve precomputed heatmaps for all legal moves from the current board.

For each legal move from the current board, this method generates a corresponding heatmap by applying the move and evaluating the resulting position with a given recursion depth.

Parameters:
depthOptional[int], default: None

The recursion depth for the heatmap calculation. If None, the engine’s current depth is used.

Returns:
Dict[Move, GradientHeatmap]

A dictionary mapping each legal move to its corresponding heatmap.

Raises:
ValueError

If the current board has no legal moves.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> move_maps = engine.get_or_calc_move_maps()
>>> some_move = list(move_maps.keys())[0]
>>> type(move_maps[some_move])
<class 'heatmaps.ChessMoveHeatmap'>
get_or_calc_move_maps_list() List[Tuple[Move, GradientHeatmap]]

Retrieve a list of move-to-heatmap mappings.

This method converts the dictionary returned by get_or_calc_move_maps() into a list of tuples for easier iteration, where each tuple contains a move and its corresponding heatmap.

Returns:
List[Tuple[Move, GradientHeatmap]]

A list of (move, heatmap) tuples.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> first_move = engine.get_or_calc_move_maps_list()[0][0]
>>> first_move
Move.from_uci('g1h3')
get_or_calc_score(board: Board) float64

Retrieve a Q-table score for board, or compute & cache a static eval if missing.

This ensures every position’s score is seeded in the Q-table before any search deeper into it.

Parameters:
boardBoard

The position for which to fetch or compute a score.

Returns:
float64

The stored or newly calculated evaluation (positive = White-good).

get_q_value(fen: Optional[str] = None, board: Optional[Board] = None, pieces_count: Optional[int] = None) Optional[float64]

Retrieve a cached Q‑value for a position, or None if uncached.

Parameters:
fenstr, optional

FEN of the position (deprecated; use board).

boardchess.Board, optional

Board object for filename lookup.

pieces_countint, optional

Override piece count for selecting DB file.

Returns:
float64 or None

Stored Q‑value, or None if no entry exists.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> q = engine.get_q_value()
static heatmap_data_is_zeros(heatmap: GradientHeatmap) bool

Check if the heatmap data is entirely zero.

Parameters:
heatmapheatmaps.GradientHeatmap

The heatmap object to check.

Returns:
bool

True if all values in the heatmap data are zero; otherwise, False.

Examples

>>> from chmengine import CMHMEngine
>>> from heatmaps import GradientHeatmap
>>> hmap = GradientHeatmap()
>>> CMHMEngine.heatmap_data_is_zeros(hmap)
True
>>> hmap[32][1] = 1.0
>>> CMHMEngine.heatmap_data_is_zeros(hmap)
False
other_player_heatmap_index(board: Optional[Board] = None) int

Get the heatmap index corresponding to the inactive (other) player.

Returns:
int

The index for the other player. Typically, if the current turn is White (index 0), this returns 1, and vice versa.

Examples

>>> from chmengine import CMHMEngine
>>> engine = CMHMEngine()
>>> engine.other_player_heatmap_index()
1
overhead: float64 = 0.0
pick_board_generator(board: Optional[Board] = None) Iterator[Tuple[Pick, Board]]

Lazily generate (Pick, Board) pairs for each legal move from board.

For each legal move: 1) Snapshot the board after the move. 2) Create Pick(move, score) where score is pulled from the Q-table

or computed on demand via get_or_calc_score.

This generator is the entry point for building the per-move cache in pick_move.

Parameters:
boardUnion[Board, None]

The position to branch from; defaults to this engine’s internal board.

Returns:
Iterator[Tuple[Pick, Board]]

An iterator over each legal move’s Pick and the resulting Board.

pick_move(*args, board: Optional[Board] = None, time_limit: Optional[float] = None, debug: bool = False, **kwargs) Pick

Choose the best move using iterative deepening on the current best branch.

If no finite time_limit is provided (and the class’s time_limit remains infinite), this will search until manually interrupted.

Otherwise, it: 1) Takes a snapshot board (defaulting to self.board or the provided board). 2) Generates all legal moves and creates a list of (Pick, Board) pairs,

with Pick.score seeded from the Q-table or a static heatmap eval.

  1. Sorts that list to find the best and second-best scores.

  2. While time remains (< deadline), calls _search_current_best_ on the top entry.

    If the second-best score ever exceeds the updated best, it re-roots by resorting to the full move list.

  3. At timeout (or if only one move), returns the Pick with the best score

    and writes that score back into the Q-table for the root position.

Parameters:
*args, **kwargspassed through to super().pick_move for fallback
boardOptional[Board]

Position to analyze; defaults to this engine’s internal board.

time_limitOptional[float]

If set, overrides the engine’s time_limit for this call.

debugbool

If True, enables verbose timing and score-change logs.

Returns:
Pick

The chosen move and its evaluation score, from the root’s perspective.

Warning

  • Without a finite time_limit, pick_move will continue indefinitely.

  • You can safely cancel an infinite search at any moment; any Q-table writes

    already performed will persist and benefit later searches.

pieces_count(board: Optional[Board] = None) int

Return the number of pieces on the board in O(1) time.

This uses Board.occupied.bit_count() when given a board.

Parameters:
boardchess.Board, optional

Board whose pieces to count. Preferred parameter.

Returns:
int

Total number of pieces on the board.

Examples

>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.pieces_count()
32
qdb_path(board: Optional[Board] = None, pieces_count: Optional[Union[int, str]] = None) str

Get the full path to the Q‑table database file.

Parameters:
boardchess.Board, optional

Board object for file naming.

pieces_countint or str, optional

Explicit piece count override.

Returns:
str

Relative path: <cache_dir>/<qtable_filename(…)>

Examples

>>> import os
>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.qdb_path() == os.path.join(engine.cache_dir, engine.qtable_filename())
True
qtable_filename(board: Optional[Board] = None, pieces_count: Optional[Union[int, str]] = None) str

Build the Q‑table filename based on depth and piece count.

Parameters:
boardchess.Board, optional

Board object to derive FEN (and piece count) if fen is not given.

pieces_countint or str, optional

Explicit piece count to use. If provided, skips recomputing from board/FEN.

Returns:
str

File name of the form “qtable_depth_{depth}_piece_count_{pieces_count}.db”.

Examples

>>> import os
>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.qtable_filename() in os.listdir(path=engine.cache_dir)
True
set_q_value(value: float, fen: Optional[str] = None, board: Optional[Board] = None, pieces_count: Optional[int] = None) None

Insert or update the Q‑value for a given position in the DB.

Parameters:
valuefloat

Q‑value to store.

fenstr, optional

Position FEN (deprecated; prefer board).

boardchess.Board, optional

Board object for filename lookup.

pieces_countint, optional

Override piece count for selecting DB file.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.set_q_value(0.0, '1k6/8/8/8/8/3K4/8/8 w - - 0 1')
time_limit: float64 = inf
update_q_values(debug: bool = False) None

Back-propagate game outcome through the Q-table.

Pops all moves from the current board history and adjusts each stored Q-value in the database based on the final result (win/lose/draw).

Parameters:
debugbool, default=False

If True, print diagnostics for each back-step.

Notes

Updates the SQLite Q-table entries for every move in the game.

Examples

>>> from io import StringIO
>>> from chess import pgn
>>> from chmengine import CMHMEngine2
>>> pgn_buffer = StringIO(
...    '''
...    1. f3 e5 2. g4 Qh4# 0-1
...
...
...    '''
... )
>>> game = pgn.read_game(pgn_buffer)
>>> board = game.board()
>>> for move in game.mainline_moves():
...     board.push(move)
>>> engine = CMHMEngine2(board=board)
>>> engine.fen()
'rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3'
>>> engine.update_q_values()
>>> engine.fen()
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
static update_target_moves_by_delta(target_moves_by_delta: List[Union[Tuple[None, None], Pick]], current_player_sum: float64, other_player_sum: float64, move: Move) List[Pick]

Update the candidate moves based on the delta between current and other player’s sums.

The delta is computed as the difference between the current player’s sum and the other player’s sum. If the calculated delta is greater than the current best, the candidate list is replaced; if equal, the move is appended.

Parameters:
target_moves_by_deltaList[Union[Tuple[None, None], Pick]]

The current list of candidate moves and their delta scores.

current_player_sumnumpy.float64

The sum of move intensities for the current player.

other_player_sumnumpy.float64

The sum of move intensities for the other player.

movechess.Move

The move being evaluated.

Returns:
List[Pick]

The updated list of candidate moves with their delta scores.

static update_target_moves_by_king_delta(target_moves_by_king_delta: List[Union[Tuple[None, None], Pick]], move: Move, current_king_min: float64, other_king_sum: float64) List[Pick]

Update candidate moves based on the king’s delta value.

Calculates the delta between the opponent’s king intensity and the current king’s minimum intensity, updating the candidate list if this delta is greater than the current best.

Parameters:
target_moves_by_king_deltaList[Union[Tuple[None, None], Pick]]

The current candidate moves for the king delta criterion.

movechess.Move

The move being evaluated.

current_king_minnumpy.float64

The minimum intensity value for the current king.

other_king_sumnumpy.float64

The total intensity value for the opponent’s king.

Returns:
List[Pick]

The updated list of candidate moves based on king delta.

static update_target_moves_by_max_current(target_moves_by_max_current: List[Union[Tuple[None, None], Pick]], transposed_map: ndarray, move: Move, color_index: int) Tuple[float64, List[Pick]]

Update the candidate moves for maximizing the current player’s intensity.

Computes the current player’s total intensity from the transposed heatmap and updates the candidate list if the new sum is greater than the current best.

Parameters:
target_moves_by_max_currentList[Union[Tuple[None, None], Pick]]

The current candidate moves for maximizing the current player’s intensity.

transposed_mapnumpy.ndarray

The transposed heatmap data array.

movechess.Move

The move being evaluated.

color_indexint

The index corresponding to the current player.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the current player’s sum and the updated candidate list.

static update_target_moves_by_max_other_king(target_moves_by_max_other_king: List[Union[Tuple[None, None], Pick]], heatmap: GradientHeatmap, move: Move, color_index: int, other_king_box: List[int]) Tuple[float64, List[Pick]]

Update candidate moves for maximizing the opponent king’s intensity.

Calculates the opponent king’s total intensity from the heatmap over the specified area and updates the candidate list if a higher intensity sum is found.

Parameters:
target_moves_by_max_other_kingList[Union[Tuple[None, None], Pick]]

The candidate moves list for maximizing opponent king’s intensity.

heatmapheatmaps.GradientHeatmap

The heatmap object containing move intensities.

movechess.Move

The move being evaluated.

color_indexint

The index corresponding to the opponent.

other_king_boxList[int]

A list of board squares representing the area around the opponent’s king.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the opponent king’s sum and the updated candidate list.

static update_target_moves_by_min_current_king(target_moves_by_min_current_king: List[Union[Tuple[None, None], Pick]], heatmap: GradientHeatmap, move: Move, other_index: int, current_king_box: List[int]) Tuple[float64, List[Pick]]

Update candidate moves for minimizing the current king’s intensity.

Extracts the intensity values for the current king from the heatmap and updates the candidate list if a lower intensity sum is found.

Parameters:
target_moves_by_min_current_kingList[Union[Tuple[None, None], Pick]]

The candidate moves list for minimizing current king’s intensity.

heatmapheatmaps.GradientHeatmap

The heatmap object containing move intensities.

movechess.Move

The move being evaluated.

other_indexint

The index corresponding to the opponent.

current_king_boxList[int]

A list of board squares representing the area around the current king.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the current king’s sum and the updated candidate list.

static update_target_moves_by_min_other(target_moves_by_min_other: List[Union[Tuple[None, None], Pick]], transposed_map: ndarray, move: Move, other_index: int) Tuple[float64, List[Pick]]

Update the candidate moves for minimizing the opponent’s sum.

Calculates the opponent’s total move intensity from the transposed heatmap, and updates the candidate list if the new sum is lower than the current best.

Parameters:
target_moves_by_min_otherList[Union[Tuple[None, None], Pick]]

The current candidate moves for minimizing the opponent’s intensity.

transposed_mapnumpy.ndarray

The transposed heatmap data array.

movechess.Move

The move being evaluated.

other_indexint

The index corresponding to the opponent.

Returns:
Tuple[float64, List[Pick]]

A tuple containing the opponent’s sum and the updated candidate list.

class chmengine.Pick(move: Move, score: Number)

Bases: PickT

Fully featured container for a (move, score) pair.

This class provides tuple-like access, type casting, and rich formatting. It extends PickT and is the public-facing API for move-score pairs.

Attributes:
move_getter_keysTuple[int, str, int]

Allowed keys to access the move.

score_getter_keysTuple[int, str, int]

Allowed keys to access the score.

property data: Tuple[Move, float64]

Read-only access to the pick data as a tuple.

Returns:
Tuple[Move, float64]

The (move, score) pair represented by this object.

property move: Move

Read-only access to the move.

Returns:
Move

The chess move associated with this Pick.

move_getter_keys: Tuple[int, str, int] = (0, 'move', -2)
property score: float64

Read access to the score.

Returns:
float64

The numeric evaluation of the move.

score_getter_keys: Tuple[int, str, int] = (1, 'score', -1)
class chmengine.PlayCMHMEngine(player_color: str = 'white', player_index: int = 0, depth: int = 1, board: Optional[Board] = None, player_name: str = 'Unknown', site: str = 'Unknown', game_round: int = 0, engine: Optional[Callable] = None, fill_initial_q_table_values: bool = False)

Bases: object

Play a game against the engine.

cpu_color: str = 'black'
cpu_index: int = 1
cpu_name: str = 'chmengine.CMHMEngine'
engine: CMHMEngine
fill_initial_q_values() None

Fills initial q-values for board state

game_round: int = 0
pgn_dir: str = 'pgns'
play(pick_by: str = 'all-delta') None

Play a game against the engine

player_color: str = 'white'
player_index: int = 0
player_name: str = 'Unknown'
round_results: List[Game]
save_to_pgn(file_name: str, game: Game) None

Saves a game to a pgn file.

Parameters:
file_namestr
game
site: str = 'Unknown'
train_cmhmey_jr(training_games: int = 1000, training_games_start: int = 0, debug: bool = False) None

Trains engine. CMHMEngine2 specifically.

Parameters:
training_gamesint
training_games_startint
debugbool
training_dir: str = 'trainings'
class chmengine.Quartney

Bases: object

Mother class of Cmhmey Jr., managing Q‑table persistence and move selection.

board: Optional[Board]
cache_dir: str = '.\\SQLite3Caches\\QTables'
property depth: int

Current search depth used for heatmap and Q‑table lookups.

Returns:
int

Depth ≥ 0.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.depth
1
abstract fen(board: Optional[Board] = None) str

Return the FEN string representing board.

Parameters:
boardchess.Board

Board to serialize.

Returns:
str

FEN string of board.

get_q_value(fen: Optional[str] = None, board: Optional[Board] = None, pieces_count: Optional[int] = None) Optional[float64]

Retrieve a cached Q‑value for a position, or None if uncached.

Parameters:
fenstr, optional

FEN of the position (deprecated; use board).

boardchess.Board, optional

Board object for filename lookup.

pieces_countint, optional

Override piece count for selecting DB file.

Returns:
float64 or None

Stored Q‑value, or None if no entry exists.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> q = engine.get_q_value()
abstract pick_move(pick_by: str = '', board: Optional[Board] = None, debug: bool = False) Pick

Select a move based on heatmap scores and update its Q‑value.

This method evaluates all legal moves on board (or on the engine’s current board if board is None), picks one of the top‑scoring moves at random, writes the new Q‑value to the database, and returns (move, score).

Parameters:
pick_bystr, default=””

Legacy parameter (ignored).

boardchess.Board, optional

Board to pick from; defaults to self.board.

debugbool, default=False

If True, print the full move‑score table.

Returns:
(chess.Move, numpy.float64)

The chosen move and its score.

Raises:
ValueError

If there are no legal moves.

Examples

>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> move, score = engine.pick_move()
pieces_count(board: Optional[Board] = None) int

Return the number of pieces on the board in O(1) time.

This uses Board.occupied.bit_count() when given a board.

Parameters:
boardchess.Board, optional

Board whose pieces to count. Preferred parameter.

Returns:
int

Total number of pieces on the board.

Examples

>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.pieces_count()
32
qdb_path(board: Optional[Board] = None, pieces_count: Optional[Union[int, str]] = None) str

Get the full path to the Q‑table database file.

Parameters:
boardchess.Board, optional

Board object for file naming.

pieces_countint or str, optional

Explicit piece count override.

Returns:
str

Relative path: <cache_dir>/<qtable_filename(…)>

Examples

>>> import os
>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.qdb_path() == os.path.join(engine.cache_dir, engine.qtable_filename())
True
qtable_filename(board: Optional[Board] = None, pieces_count: Optional[Union[int, str]] = None) str

Build the Q‑table filename based on depth and piece count.

Parameters:
boardchess.Board, optional

Board object to derive FEN (and piece count) if fen is not given.

pieces_countint or str, optional

Explicit piece count to use. If provided, skips recomputing from board/FEN.

Returns:
str

File name of the form “qtable_depth_{depth}_piece_count_{pieces_count}.db”.

Examples

>>> import os
>>> from chmengine.engines.cmhmey2 import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.qtable_filename() in os.listdir(path=engine.cache_dir)
True
set_q_value(value: float, fen: Optional[str] = None, board: Optional[Board] = None, pieces_count: Optional[int] = None) None

Insert or update the Q‑value for a given position in the DB.

Parameters:
valuefloat

Q‑value to store.

fenstr, optional

Position FEN (deprecated; prefer board).

boardchess.Board, optional

Board object for filename lookup.

pieces_countint, optional

Override piece count for selecting DB file.

Examples

>>> from chmengine import CMHMEngine2
>>> engine = CMHMEngine2()
>>> engine.set_q_value(0.0, '1k6/8/8/8/8/3K4/8/8 w - - 0 1')
abstract update_q_values(debug: bool = False) None

Back-propagate game outcome through the Q-table.

Pops all moves from the current board history and adjusts each stored Q-value in the database based on the final result (win/lose/draw).

Parameters:
debugbool, default=False

If True, print diagnostics for each back-step.

Notes

Updates the SQLite Q-table entries for every move in the game.

Examples

>>> from io import StringIO
>>> from chess import pgn
>>> from chmengine import CMHMEngine2
>>> pgn_buffer = StringIO(
...    '''
...    1. f3 e5 2. g4 Qh4# 0-1
...
...
...    '''
... )
>>> game = pgn.read_game(pgn_buffer)
>>> board = game.board()
>>> for move in game.mainline_moves():
...     board.push(move)
>>> engine = CMHMEngine2(board=board)
>>> engine.fen()
'rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3'
>>> engine.update_q_values()
>>> engine.fen()
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
chmengine.better_checkmate_score(board: Board, depth: int) float64

Compute an enhanced checkmate evaluation score.

This function returns a large-magnitude score to represent a checkmate outcome, scaled by the number of pieces remaining, the search depth, and an additional safety margin multiplier. By multiplying by 64 (squares) and 27 (maximum queen moves), we ensure that non-checkmate positional scores remain bounded in comparison.

The sign encodes which side is to move: - If it is White’s turn (i.e., White has just been checkmated), returns a

large negative score (bad for White).

  • If it is Black’s turn (i.e., Black has just been checkmated), returns

    a large positive score (good for White).

Parameters:
boardchess.Board

The board position where checkmate has occurred.

depthint

The recursion depth used in the evaluation, included to amplify the score further for deeper searches.

Returns:
numpy.float64

A signed checkmate score with large magnitude, where positive values favor White and negative values favor Black.

chmengine.calculate_better_white_minus_black_score(board: Board, depth: int = 1) float64

Compute an enhanced White-minus-Black evaluation for a given board position.

This function combines three components into a single signed score:

  1. Game termination:
    • If the position is a draw, returns 0.

    • If the position is checkmate, returns a high upper-bound value via checkmate_score().

  2. Heatmap mobility delta:

    Difference in total possible moves between White and Black, computed by calculate_chess_move_heatmap_with_better_discount().

  3. King-box mobility delta:

    Difference in potential moves targeting the opponent’s king region and defending the own king region.

  4. Static delta:

    Material-mobility delta from get_static_delta_score().

The final score is the sum of the mobility delta, king-box delta, and static delta, representing White’s advantage minus Black’s.

Parameters:
boardchess.Board

The chess board position to evaluate.

depthint, default: 1

Recursion depth for the heatmap calculation. Higher values yield more thorough mobility estimates at the cost of increased computation time.

Returns:
numpy.float64

The signed evaluation: positive values favor White, negative values favor Black.

Notes

  • Time complexity is O(b^d) for the heatmap portion (where b ≈ 35 is the branching factor).

  • Checkmate scores use an upper-bound heuristic: all remaining pieces can move to every square,

    scaled by (depth + 1).

chmengine.calculate_white_minus_black_score(board: Board, depth: int) float64

Evaluate the board from a White-minus-Black perspective using heatmap evaluation.

This function returns a net evaluation score. Positive values favor White, negative values favor Black. Terminal game states return fixed scores. Otherwise, the score is derived from: - Heatmap intensity differences - Control over king box areas

Parameters:
boardchess.Board

The chess board to evaluate.

depthint

Depth of future move evaluation.

Returns:
numpy.float64

Net evaluation score (White - Black). Terminal states return extreme values.

Examples

>>> from chmengine.utils import is_draw
>>> from chess import Board, Move
>>> default_board, d = Board(), 1
>>> calculate_white_minus_black_score(board=default_board, depth=d)
0.0
>>> default_board.push(Move.from_uci('e2e4'))
>>> calculate_white_minus_black_score(board=default_board, depth=d)
10.0
>>> default_board.push(Move.from_uci('e7e5'))
>>> calculate_white_minus_black_score(board=default_board, depth=d)
0.20689655172414234
>>> default_board.push(Move.from_uci('g1f3'))
>>> calculate_white_minus_black_score(board=default_board, depth=d)
-2.1379310344827616
>>> default_board.push(Move.from_uci('b8c6'))
>>> calculate_white_minus_black_score(board=default_board, depth=d)
-3.925925925925924
>>> default_board.push(Move.from_uci('f1b5'))
>>> calculate_white_minus_black_score(board=default_board, depth=d)
2.133333333333335
>>> mate_board = Board('8/2p2p2/4p3/2k5/8/6q1/2K5/1r1q4 w - - 2 59')
>>> calculate_white_minus_black_score(board=mate_board, depth=d)
-1024.0
>>> draw_board = Board('6R1/7p/2p2p1k/p1P2Q2/P7/6K1/5P2/8 b - - 0 52')
>>> calculate_white_minus_black_score(board=draw_board, depth=d)
0.0
chmengine.checkmate_score(board: Board, depth: int) float64

Return a large signed score for checkmate results.

The score is scaled by number of remaining pieces and depth. Negative if the current player is mated, positive if they deliver mate.

Parameters:
boardchess.Board

Board state assumed to be in a terminal position.

depthint

Search depth used, for scaling the final score.

Returns:
numpy.float64

Large positive or negative score depending on the outcome.

Examples

>>> from chmengine.utils import is_draw
>>> from chess import Board
>>> blk_win_board = Board('8/2p2p2/4p3/2k5/8/6q1/2K5/1r1q4 w - - 2 59')
>>> checkmate_score(board=blk_win_board, depth=1)
-1024.0
chmengine.format_moves(picks: List[Pick]) List[Tuple[str, str]]

Format a list of (move, score) tuples into UCI strings and formatted scores.

Parameters:
picksList[Pick]

The list of Picks (moves and their evaluation scores.)

Returns:
List[Tuple[str, str]

Formatted list where each tuple contains the move in UCI format and the score rounded to two decimal places. Entries with None moves are excluded.

chmengine.format_picks(picks: List[Pick]) str

Format a list of Picks into UCI strings and formatted scores.

Parameters:
picksList[Pick]

The list of Picks (moves and their evaluation scores.)

Returns:
str

Formatted list where each tuple contains the move in UCI format and the score rounded to two decimal places. Entries with None moves are excluded.

chmengine.get_static_delta_score(heatmap: ChessMoveHeatmap) float64

Compute the static piece-based delta score from a ChessMoveHeatmap.

This function multiplies each piece’s move count (from the heatmap’s piece_counts) by its static movement value (from get_static_value) and returns the difference between White’s total and Black’s total. It serves as a simple material–mobility heuristic.

Parameters:
heatmapheatmaps.ChessMoveHeatmap

The heatmap object containing per-piece move counts for each square.

Returns:
numpy.float64

The signed delta score: (White’s static total) − (Black’s static total).

chmengine.get_static_value(piece: Piece) int

Retrieve the static movement-based value for a given chess piece.

This function returns a fixed integer value representing the maximum number of moves that the specified piece can make on an empty board. These values serve as a simple heuristic for piece mobility.

Parameters:
piecechess.Piece

The chess piece for which to look up the static move value.

Returns:
int

The static movement value for the piece, or 0 if the piece is not in the map.

chmengine.get_white_and_black_king_boxes(board: Board) Tuple[List[int], List[int]]

Compute the list of squares surrounding each king on the board.

These “king boxes” are used for evaluating positional pressure around the kings.

Parameters:
boardBoard

The board from which to extract king square surroundings.

Returns:
Tuple[List[int], List[int]]

Tuple containing white king box and black king box square indices. (white_king_box, black_king_box)

Examples

>>> from chmengine.utils import is_draw
>>> from chess import Board
>>> white_kb, black_kb = get_white_and_black_king_boxes(board=Board())
>>> sorted(white_kb), sorted(black_kb)
([3, 4, 5, 11, 12, 13], [51, 52, 53, 59, 60, 61])
chmengine.insert_ordered_best_to_worst(ordered_picks: List[Pick], pick: Pick) None

Insert a move into a list of moves sorted from best to worst.

Parameters:
ordered_picksList[Pick]

Existing list sorted in descending order of score.

pickPick
chmengine.insert_ordered_worst_to_best(ordered_picks: List[Pick], pick: Pick) None

Insert a move into a list of moves sorted from worst to best.

Parameters:
ordered_picksList[Pick]

Existing list sorted in ascending order of score.

pickPick
chmengine.is_draw(winner: Optional[bool]) bool

Check if a game result is a draw based on the winner field.

Parameters:
winnerbool or None

Result of Board.outcome(…).winner. True for White win, False for Black win, None for draw.

Returns:
bool

True if the game is a draw, False otherwise.

Examples

>>> from chmengine.utils import is_draw
>>> from chess import Board
>>> mate_board = Board('8/2p2p2/4p3/2k5/8/6q1/2K5/1r1q4 w - - 2 59')
>>> is_draw(mate_board.outcome(claim_draw=True).winner)
False
>>> draw_board = Board('6R1/7p/2p2p1k/p1P2Q2/P7/6K1/5P2/8 b - - 0 52')
>>> is_draw(draw_board.outcome(claim_draw=True).winner)
True
chmengine.pieces_count_from_board(board: Board) int

Return the number of pieces on the board

This uses the internal bitboard to count occupied squares in O(1) time. On Python ≥ 3.8 it calls int.bit_count(). On Python 3.7 it falls back to bin(…).count(‘1’) for compatibility.

Parameters:
boardchess.Board

A board object to count pieces from

Returns:
int

Number of pieces on the board.

Examples

>>> from chess import Board
>>> mate_board = Board('8/2p2p2/4p3/2k5/8/6q1/2K5/1r1q4 w - - 2 59')
>>> pieces_count_from_board(mate_board)
8
>>> pieces_count_from_board(Board())
32
chmengine.pieces_count_from_fen(fen: str) int

Return the number of pieces on the board represented by fen.

This function converts the FEN string into a Board object, then uses the internal bitboard to count occupied squares in O(1) time. On Python ≥ 3.8, it calls int.bit_count(); on Python 3.7, it falls back to bin(…).count(‘1’) for compatibility.

Parameters:
fenstr

A full FEN string representing a chess position.

Returns:
int

The count of non‑empty squares (i.e. total pieces) on the board.

Notes

For most use cases, especially when you already have a Board object, prefer using pieces_count_from_board(board) instead. This avoids the overhead of FEN parsing and achieves the same result more efficiently.

Examples

>>> from chess import Board
>>> pieces_count_from_fen('8/2p2p2/4p3/2k5/8/6q1/2K5/1r1q4 w - - 2 59')
8
>>> pieces_count_from_fen(Board().fen())
32
chmengine.set_all_datetime_headers(game_heads: Headers, local_time: datetime) None

Sets all datetime related game headers for the pgn file.

Parameters:
game_headschess.pgn.Headers
local_timedatetime.datetime
chmengine.set_utc_headers(game_heads: Headers, local_time: datetime) None

Sets UTC header info of pgn file data from local timestamp

Parameters:
game_headschess.pgn.Headers
local_timedatetime.datetime

Modules

chmengine.engines

Engines

chmengine.play

Play or Train the engine(s)

chmengine.utils

Utilities for engine evaluation and scoring logic.