def find_puzzle_candidates(game: Game, scan_depth=SCAN_DEPTH) -> List[Puzzle]: """ finds puzzle candidates from a chess game """ log(Color.DIM, "Scanning game for puzzles (depth: %d)..." % scan_depth) prev_score = Cp(0) puzzles = [] i = 0 node = game while not node.is_end(): next_node = node.variation(0) next_board = next_node.board() cur_score = AnalysisEngine.best_move(next_board, scan_depth).score board = node.board() highlight_move = False if should_investigate(prev_score, cur_score, board): highlight_move = True puzzle = Puzzle( board, next_node.move, ) puzzles.append(puzzle) log_move(board, next_node.move, cur_score, highlight=highlight_move) prev_score = cur_score node = next_node i += 1 return puzzles
def _analyze(board, depth, **kwargs) -> Union[List[InfoDict], InfoDict]: try: info = AnalysisEngine.instance().analyse(board, Limit(depth=depth), **kwargs) except EngineTerminatedError: log(Color.RED, "Analysis engine crashed... restarting") AnalysisEngine.quit() info = AnalysisEngine._analyze(board, depth, **kwargs) return info
def _calculate_candidate_moves(self, depth): """ Find the best move from board position using multipv 3 """ multipv = NUM_CANDIDATE_MOVES log(Color.BLACK, "Evaluating best %d moves (depth %d)..." % (multipv, depth)) self.candidate_moves = AnalysisEngine.best_moves(self.board, depth, multipv) for analyzed_move in self.candidate_moves: self._log_move(analyzed_move.move, analyzed_move.score)
def _calculate_best_move(self, depth): """ Find the best move from board position using multipv 1 """ log(Color.BLACK, "Evaluating best move (depth %d)..." % depth) best_move = AnalysisEngine.best_move(self.board, depth) self.best_move = best_move.move self.score = best_move.score if self._num_legal_moves() == 1: self.candidate_moves = [best_move] self._log_move(self.best_move, self.score)
def _analyze_best_initial_move(self, depth) -> Move: log(Color.BLACK, "Evaluating best initial move (depth %d)..." % depth) best_move = AnalysisEngine.best_move(self.initial_board, depth) if best_move.move: self.analyzed_moves.append(best_move) log_move(self.initial_board, best_move.move, best_move.score, show_uci=True) self.initial_score = best_move.score return best_move.move
def _analyze_initial_moves(self, depth): """ get the score of the position before the initial move also get the score of the position after the initial move """ best_move = self._analyze_best_initial_move(depth) if not self.initial_move: return elif self.initial_move == best_move: log(Color.BLACK, "The move played was the best move") else: log(Color.BLACK, "Evaluating played initial move (depth %d)..." % depth) analyzed_move = AnalysisEngine.evaluate_move( self.initial_board, self.initial_move, depth) self.analyzed_moves.append(analyzed_move) log_move(self.initial_board, self.initial_move, analyzed_move.score, show_uci=True)
def _log_position(self): if self.initial_move: move_san = self.initial_board.san(self.initial_move) log( Color.VIOLET, "\nAfter %s %s" % (fullmove_string(self.initial_board).strip(), move_san)) log_board(self.board) log(Color.DARK_BLUE, "Material difference: %d" % material_difference(self.board)) log(Color.DARK_BLUE, "# legal moves: %d" % self._num_legal_moves())
def generate(self, depth): """ Generate new positions for the puzzle until a final position is reached """ log_board(self.initial_board) self._analyze_initial_moves(depth) self._set_initial_position() position = self.initial_position position.evaluate(depth) self.player_moves_first = self._player_moves_first() is_player_move = not self.player_moves_first while True: self.positions.append(position) if position.is_final(is_player_move): log_str = "Not going deeper: " if position.is_ambiguous(): log_str += "ambiguous" elif position.board.is_game_over(): log_str += "game over" log(Color.YELLOW, log_str) break else: log_str = "Going deeper..." if is_player_move is not None: if is_player_move: if len(position.candidate_moves) == 1: log_str += " only one move" else: log_str += " one clear best move" else: log_str += " not player move" log(Color.DIM, log_str) position = PuzzlePosition(position.board, position.best_move) position.evaluate(depth) is_player_move = not is_player_move self._calculate_final_score(depth) if self.is_complete(): log(Color.GREEN, "Puzzle is complete") else: log(Color.RED, "Puzzle incomplete")
def print_puzzle_pgn(puzzle, pgn_headers=None): puzzle_pgn = puzzle.to_pgn(pgn_headers=pgn_headers) log(Color.MAGENTA, "NEW PUZZLE GENERATED\n") print(Color.CYAN + puzzle_pgn + "\n\n" + Color.ENDC)
if settings.quiet: configure_logging(level=logging.INFO) else: configure_logging(level=logging.DEBUG) def print_puzzle_pgn(puzzle, pgn_headers=None): puzzle_pgn = puzzle.to_pgn(pgn_headers=pgn_headers) log(Color.MAGENTA, "NEW PUZZLE GENERATED\n") print(Color.CYAN + puzzle_pgn + "\n\n" + Color.ENDC) # load a FEN and try to create a puzzle from it if settings.fen: log(Color.DIM, AnalysisEngine.name()) puzzle = Puzzle(Board(settings.fen)) puzzle.generate(depth=settings.search_depth) if puzzle.is_complete(): print_puzzle_pgn(puzzle) engine.quit() exit(0) # load games from a PGN and scan them for puzzles n_positions = 0 # number of positions considered n_puzzles = 0 # number of puzzles generated game_id = 0 pgn = open(settings.pgn, "r") while game_id < settings.start_index: