Esempio n. 1
0
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
Esempio n. 2
0
    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)
Esempio n. 3
0
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()
Esempio n. 5
0
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())
Esempio n. 6
0
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"]))
Esempio n. 7
0
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())
Esempio n. 9
0
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
Esempio n. 10
0
 def test_found_answer(self):
     p = Puzzle('1234567X8')
     last_item = dfs_with_limit(p, 10)
     must_be = '12345678X'
     self.assertEqual(last_item, must_be)
Esempio n. 11
0
 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)
Esempio n. 12
0
 def test_not_solvable(self):
     p = Puzzle('812X43765')
     solvable, numofnodes, res = ids(p)
     self.assertFalse(solvable)
Esempio n. 13
0
 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)
Esempio n. 14
0
 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)
Esempio n. 15
0
 def test_path_finding(self):
     p = Puzzle('8672543X1')
     solvable, numofnodes, data = astar(p)
     self.assertEqual(solvable, True)
Esempio n. 16
0
    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)