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 test_found_answer(self): p1 = Puzzle('1234567X8') solvable, numofnodes, data = ids(p1) must_be = (True, Puzzle('12345678X')) self.assertEqual((solvable, data[-1]), must_be) p2 = Puzzle('X13425786') solvable, numofnodes, data = ids(p2) must_be = (True, Puzzle('12345678X')) self.assertEqual((solvable, data[-1]), must_be)
def ajax(): DEFAULT_STATE = Puzzle('12345678X') solvable = num_of_nodes = path = None data = request.get_json() approach = data.get('approach', None) state = Puzzle(data.get('state', DEFAULT_STATE)) # select the correct approach solvable, num_of_nodes, path = astar(state) if approach == 'astar' else ids(state) result = util.shapeshift(path) if solvable else None return jsonify({'solvable': solvable, 'level': len(result), 'num_of_nodes': num_of_nodes, 'data': result})
def test_invalid_states(self): state1 = Puzzle('12345') with self.assertRaises(ValueError): state1.generate_states() state2 = Puzzle('123456789') with self.assertRaises(ValueError): state2.generate_states()
def read(doc) -> Puzzle: board = Board(doc["fen"]) node = Game.from_board(board) for uci in doc["moves"]: move = Move.from_uci(uci) node = node.add_main_variation(move) return Puzzle(doc["_id"], node.game())
def read(doc) -> Puzzle: board = Board(doc["fen"]) node: GameNode = Game.from_board(board) for uci in (doc["line"].split(' ') if "line" in doc else doc["moves"]): move = Move.from_uci(uci) node = node.add_main_variation(move) return Puzzle(doc["_id"], node.game(), int(doc["cp"]))
def main() -> None: sys.setrecursionlimit(10000) # else node.deepcopy() sometimes fails? parser = argparse.ArgumentParser(prog='tagger.py', description='automatically tags lichess puzzles') parser.add_argument("--verbose", "-v", help="increase verbosity", action="count") args = parser.parse_args() if args.verbose == 1: logger.setLevel(logging.DEBUG) mongo = pymongo.MongoClient() db = mongo['puzzler'] puzzle_coll = db['puzzle2'] tag_coll = db['tag'] for puzzle in puzzle_coll.find(): # prev = tag_coll.find_one({"_id":puzzle._id}) board = Board(puzzle["fen"]) node = Game.from_board(board) for uci in puzzle["moves"]: move = Move.from_uci(uci) node = node.add_main_variation(move) puzzle = Puzzle(puzzle["_id"], node.game()) tags = cook.cook(puzzle) for tag in tags: tag_coll.update_one({"_id":puzzle.id},{"$addToSet":{tag: "lichess"}}, upsert = True)
def test_solvable(self): # solvable case # 1 | 8 | 2 # ---------- # | 4 | 3 # ---------- # 7 | 6 | 5 p1 = Puzzle('182X43765') self.assertTrue(p1.solvable()) # not solvable case # 8 | 1 | 2 # ---------- # | 4 | 3 # ---------- # 7 | 6 | 5 p2 = Puzzle('812X43765') self.assertFalse(p2.solvable())
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 test_found_answer(self): p = Puzzle('1234567X8') last_item = dfs_with_limit(p, 10) must_be = '12345678X' self.assertEqual(last_item, must_be)
def test_hardest_case(self): p1 = Puzzle('8672543X1') solvable, numofnodes, data = ids(p1) must_be = (True, Puzzle('12345678X')) self.assertEqual((solvable, data[-1]), must_be)
def test_not_solvable(self): p = Puzzle('812X43765') solvable, numofnodes, res = ids(p) self.assertFalse(solvable)
def test_not_found(self): # a limit with less value might be lead to not 'found' p = Puzzle('123456X78') data = dfs_with_limit(p, 1) # limit is zero self.assertEqual(data, None)
def test_manhattan_calculation(self): # 7, 2, 4, 5, 0, 6, 8, 3, 1 p = Puzzle('64785X321') manhattan = manhattan_dist(p) must_be = 21 self.assertEqual(manhattan, must_be)
def test_path_finding(self): p = Puzzle('8672543X1') solvable, numofnodes, data = astar(p) self.assertEqual(solvable, True)
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
def test_generate_states(self): state = Puzzle('12345678X') possible_states = state.generate_states() must_be = [Puzzle('12345X786'), Puzzle('1234567X8')] self.assertCountEqual(possible_states, must_be)