def analyze_position(server: Server, engine: SimpleEngine, node: GameNode, prev_score: Score, current_eval: PovScore) -> Union[Puzzle, Score]: board = node.board() winner = board.turn score = current_eval.pov(winner) if board.legal_moves.count() < 2: return score game_url = node.game().headers.get("Site") logger.debug("{} {} to {}".format(node.ply(), node.move.uci() if node.move else None, score)) if prev_score > Cp(400): logger.debug("{} Too much of a winning position to start with {} -> {}".format(node.ply(), prev_score, score)) return score if is_up_in_material(board, winner): logger.debug("{} already up in material {} {} {}".format(node.ply(), winner, material_count(board, winner), material_count(board, not winner))) return score elif score >= Mate(1) and not allow_one_mover: logger.debug("{} mate in one".format(node.ply())) return score elif score > mate_soon: logger.info("Mate {}#{} Probing...".format(game_url, node.ply())) if server.is_seen_pos(node): logger.info("Skip duplicate position") return score mate_solution = cook_mate(engine, copy.deepcopy(node), winner) server.set_seen(node.game()) return Puzzle(node, mate_solution) if mate_solution is not None else score elif score >= Cp(0) and win_chances(score) > win_chances(prev_score) + 0.5: if score < Cp(400) and material_diff(board, winner) > -1: logger.info("Not clearly winning and not from being down in material, aborting") return score logger.info("Advantage {}#{} {} -> {}. Probing...".format(game_url, node.ply(), prev_score, score)) if server.is_seen_pos(node): logger.info("Skip duplicate position") return score puzzle_node = copy.deepcopy(node) solution : Optional[List[NextMovePair]] = cook_advantage(engine, puzzle_node, winner) server.set_seen(node.game()) if not solution: return score while len(solution) % 2 == 0 or not solution[-1].second: if not solution[-1].second: logger.info("Remove final only-move") solution = solution[:-1] if not solution or (len(solution) == 1 and not allow_one_mover): logger.info("Discard one-mover") return score last = list(puzzle_node.mainline())[len(solution)] gain = material_diff(last.board(), winner) - material_diff(board, winner) if gain > 1 or ( len(solution) == 1 and win_chances(solution[0].best.score) > win_chances(solution[0].second.score) + 0.5): return Puzzle(node, [p.best.move for p in solution]) return score else: return score
def is_valid_mate_in_one(pair: NextMovePair, engine: SimpleEngine) -> bool: if pair.best.score != Mate(1): return False non_mate_win_threshold = 0.6 if not pair.second or win_chances(pair.second.score) <= non_mate_win_threshold: return True if pair.second.score == Mate(1): # if there's more than one mate in one, gotta look if the best non-mating move is bad enough logger.debug('Looking for best non-mating move...') info = engine.analyse(pair.node.board(), multipv = 5, limit = pair_limit) for score in [pv["score"].pov(pair.winner) for pv in info]: if score < Mate(1) and win_chances(score) > non_mate_win_threshold: return False return True return False
def is_valid_mate_in_one(pair: NextMovePair, engine: YaneuraOu) -> bool: if pair.best.score != Mate(1): return False non_mate_win_threshold = 0.85 if not pair.second or win_chances( pair.second.score) <= non_mate_win_threshold: return True return False
def is_valid_attack(pair: NextMovePair) -> bool: if pair.second is None: return True if pair.best.score == Mate(1): return True if pair.best.score == Mate(2): return pair.second.score < Cp(500) if pair.best.score == Mate(3): return pair.second.score < Cp(300) if win_chances(pair.best.score) > win_chances(pair.second.score) + 0.5: return True # if best move is mate, and second move still good but doesn't win material, # then best move is valid attack if pair.best.score.is_mate() and pair.second.score < Cp(400): next_node = pair.node.add_variation(pair.second.move) return not "x" in next_node.san() return False
def is_valid_attack(pair: NextMovePair, engine: SimpleEngine) -> bool: return ( pair.second is None or is_valid_mate_in_one(pair, engine) or win_chances(pair.best.score) > win_chances(pair.second.score) + 0.7 )
def analyze_position( server: Server, engine: YaneuraOu, node: Node, prev_score: Score, current_eval: PovScore, args: argparse.Namespace) -> Tuple[Score, Optional[Puzzle]]: board = node.board() winner = board.turn score = current_eval.pov(winner) logger.debug("\nAnalyzing position, scores: {} -> {}".format( prev_score, score)) if sum(1 for i in board.legal_moves) < 2: logger.debug("Not enough legal moves.") return score, None logger.debug("{} {} to {}".format(node.current_board.move_number, node.move() if node.move() else None, score)) if prev_score > Cp(3000) and score < mate_soon: logger.debug( "{} Too much of a winning position to start with {} -> {}".format( node.current_board.move_number, prev_score, score)) return score, None if is_up_in_material(board, winner) and prev_score > Cp(2200): logger.debug("{} already up in material {} {} {}".format( node.current_board.move_number, winner, material_count(board, winner), material_count(board, not winner))) return score, None elif score >= Mate(1) and not allow_one_mater: logger.debug("{} mate in one".format(node.current_board.move_number)) return score, None elif score > mate_soon: logger.debug("Mate {}. {} Probing...".format( node.current_board.move_number, score)) if server.is_seen_pos(node): logger.debug("Skip duplicate position") return score, None mate_solution = cook_mate(engine, copy.deepcopy(node), winner) server.set_seen(node) return score, Puzzle(node, mate_solution, 999999999) if mate_solution is not None else None elif win_chances(score) > win_chances(prev_score) + 0.40: if score < Cp(750) and win_chances( score) < win_chances(prev_score) + 0.50: logger.debug( "Not clearly winning and not equalizing enough, aborting") return score, None logger.debug("Advantage {}. {} -> {}. Probing...".format( node.current_board.move_number, prev_score, score)) if server.is_seen_pos(node): logger.debug("Skip duplicate position") return score, None puzzle_node = copy.deepcopy(node) solution: Optional[List[NextMovePair]] = cook_advantage( engine, puzzle_node, winner) server.set_seen(node) if not solution: return score, None while len(solution) % 2 == 0 or not solution[-1].second: if not solution[-1].second: logger.debug("Remove final only-move") solution = solution[:-1] if not solution or len(solution) == 1: logger.debug("Discard one-mover") return score, None cp = solution[len(solution) - 1].best.score.score() return score, Puzzle(node, [p.best.move for p in solution], 999999998 if cp is None else cp) else: logger.debug("Nothing, {}, {}".format(score, win_chances(score))) return score, None
def is_valid_defense(pair: NextMovePair) -> bool: return True if pair.second is None or pair.second.score == Mate(1): return True return win_chances(pair.second.score) > win_chances(pair.best.score) + 0.25
def is_valid_attack(self, pair: NextMovePair) -> bool: return (pair.second is None or self.is_valid_mate_in_one(pair) or win_chances( pair.best.score) > win_chances(pair.second.score) + 0.7)
def analyze_position(self, node: ChildNode, prev_score: Score, current_eval: PovScore, tier: int) -> Union[Puzzle, Score]: board = node.board() winner = board.turn score = current_eval.pov(winner) if board.legal_moves.count() < 2: return score game_url = node.game().headers.get("Site") logger.debug("{} {} to {}".format( node.ply(), node.move.uci() if node.move else None, score)) if prev_score > Cp(300) and score < mate_soon: logger.debug( "{} Too much of a winning position to start with {} -> {}". format(node.ply(), prev_score, score)) return score if is_up_in_material(board, winner): logger.debug("{} already up in material {} {} {}".format( node.ply(), winner, material_count(board, winner), material_count(board, not winner))) return score elif score >= Mate(1) and tier < 3: logger.debug("{} mate in one".format(node.ply())) return score elif score > mate_soon: logger.debug("Mate {}#{} Probing...".format(game_url, node.ply())) if self.server.is_seen_pos(node): logger.debug("Skip duplicate position") return score mate_solution = self.cook_mate(copy.deepcopy(node), winner) if mate_solution is None or (tier == 1 and len(mate_solution) == 3): return score return Puzzle(node, mate_solution, 999999999) elif score >= Cp(200) and win_chances( score) > win_chances(prev_score) + 0.6: if score < Cp(400) and material_diff(board, winner) > -1: logger.debug( "Not clearly winning and not from being down in material, aborting" ) return score logger.debug("Advantage {}#{} {} -> {}. Probing...".format( game_url, node.ply(), prev_score, score)) if self.server.is_seen_pos(node): logger.debug("Skip duplicate position") return score puzzle_node = copy.deepcopy(node) solution: Optional[List[NextMovePair]] = self.cook_advantage( puzzle_node, winner) self.server.set_seen(node.game()) if not solution: return score while len(solution) % 2 == 0 or not solution[-1].second: if not solution[-1].second: logger.debug("Remove final only-move") solution = solution[:-1] if not solution or len(solution) == 1: logger.debug("Discard one-mover") return score if tier < 3 and len(solution) == 3: logger.debug("Discard two-mover") return score cp = solution[len(solution) - 1].best.score.score() return Puzzle(node, [p.best.move for p in solution], 999999998 if cp is None else cp) else: return score