Ejemplo n.º 1
0
 def _parse_game(game: Game) -> List[str]:
     positions: List[str] = []
     board = game.board()
     for move in game.mainline_moves():
         board.push(move)
         positions.append(board.fen())
     return positions
Ejemplo n.º 2
0
def start_new_game(temporary=False):
    base = 'tmp' if temporary else str(int(time.time()))
    fn = os.path.extsep.join([base, 'pgn'])
    path = games_path(fn)
    _logger().info("Starting new game '{}'...".format(path))
    game = Game()
    game.headers["Date"] = time.strftime("%Y.%m.%d")
    game.headers["White"] = "Human"
    game.headers["Black"] = "Raspberry Turk"
    _save_game(game, path)
    enter_game(fn)
Ejemplo n.º 3
0
def mate_in(game: Game) -> Optional[TagKind]:
    if not game.end().board().is_checkmate():
        return None
    moves_to_mate = int(len(list(game.mainline_moves())) / 2)
    if moves_to_mate == 2:
        return "mateIn2"
    elif moves_to_mate == 2:
        return "mateIn2"
    elif moves_to_mate == 3:
        return "mateIn3"
    elif moves_to_mate == 4:
        return "mateIn4"
    elif moves_to_mate == 5:
        return "mateIn5"
    return "mateIn6+"
Ejemplo n.º 4
0
 def get_puzzle(self, fen: str, prev_score: Score, move: str, current_score: Score, moves: str) -> None:
     board = Board(fen)
     game = Game.from_board(board)
     node = game.add_main_variation(Move.from_uci(move))
     current_eval = PovScore(current_score, not board.turn)
     result = self.gen.analyze_position(node, prev_score, current_eval, tier=10)
     self.assert_is_puzzle_with_moves(result, [Move.from_uci(x) for x in moves.split()])
Ejemplo n.º 5
0
    def learn(self, iters=100, c=10):
        """
        Run the Q-learning algorithm. Play greedy on the final iter
        Args:
            iters: int
                amount of games to train
            c: int
                update the network every c games

        Returns: pgn (str)
            pgn string describing final game

        """
        for k in range(iters):
            if k % c == 0:
                print("iter", k)
                self.agent.fix_model()
            greedy = True if k == iters - 1 else False
            self.env.reset()
            self.play_game(k, greedy=greedy)

        pgn = Game.from_board(self.env.board)
        reward_smooth = pd.DataFrame(self.reward_trace)
        reward_smooth.rolling(window=10, min_periods=0).mean().plot()

        return pgn
Ejemplo n.º 6
0
def analyze_game(server: Server, engine: SimpleEngine, game: Game,
                 args: argparse.Namespace) -> Optional[Puzzle]:

    logger.debug("Analyzing game {}...".format(game.headers.get("Site")))

    prev_score: Score = Cp(20)

    for node in game.mainline():

        current_eval = node.eval()

        if not current_eval:
            logger.debug("Skipping game without eval on ply {}".format(
                node.ply()))
            return None

        result = analyze_position(server, engine, node, prev_score,
                                  current_eval, args)

        if isinstance(result, Puzzle):
            return result

        prev_score = -result

    logger.debug("Found nothing from {}".format(game.headers.get("Site")))

    return None
Ejemplo n.º 7
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())
Ejemplo n.º 8
0
 def not_puzzle(self, fen: str, prev_score: Score, move: str, current_score: Score) -> None:
     board = Board(fen)
     game = Game.from_board(board)
     node = game.add_main_variation(Move.from_uci(move))
     current_eval = PovScore(current_score, not board.turn)
     result = self.gen.analyze_position( node, prev_score, current_eval, tier=10)
     self.assertIsInstance(result, Score)
Ejemplo n.º 9
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"]))
Ejemplo n.º 10
0
def clean(game: Game) -> None:
    for node in game.mainline():
        for variation in reversed(node.variations):
            if not variation.is_mainline():
                node.remove_variation(variation.move)

        node.nags = set()
        node.comment = ""
Ejemplo n.º 11
0
    def analyze_game(self, game: Game, tier: int) -> Optional[Puzzle]:

        logger.debug(f'Analyzing tier {tier} {game.headers.get("Site")}...')

        prev_score: Score = Cp(20)
        seen_epds: Set[str] = set()
        board = game.board()
        skip_until_irreversible = False

        for node in game.mainline():
            if skip_until_irreversible:
                if board.is_irreversible(node.move):
                    skip_until_irreversible = False
                    seen_epds.clear()
                else:
                    board.push(node.move)
                    continue

            current_eval = node.eval()

            if not current_eval:
                logger.debug("Skipping game without eval on ply {}".format(
                    node.ply()))
                return None

            board.push(node.move)
            epd = board.epd()
            if epd in seen_epds:
                skip_until_irreversible = True
                continue
            seen_epds.add(epd)

            if board.castling_rights != maximum_castling_rights(board):
                continue

            result = self.analyze_position(node, prev_score, current_eval,
                                           tier)

            if isinstance(result, Puzzle):
                return result

            prev_score = -result

        logger.debug("Found nothing from {}".format(game.headers.get("Site")))

        return None
Ejemplo n.º 12
0
    def export(puzzle, include_first_move=True):
        fen = puzzle.last_pos.fen()
        board = chess.Board(fen)
        game = Game().from_board(board)

        result = PgnExporter.determine_result_tag(board)
        moves = puzzle.positions.move_list()

        if include_first_move:
            first_move = puzzle.last_move
        else:
            # simulate the move (blunder)
            board.push(puzzle.last_move)
            board.clear_stack()
            # take resulting board and create new game
            game = Game().from_board(board)

            first_move = Move.from_uci(moves.pop(0))

        # start the line
        node = game.add_main_variation(first_move)

        # add the rest of the moves
        for m in moves:
            node = node.add_variation(Move.from_uci(m))

        # copy headers from the original game and override result tag
        for h in puzzle.game.headers:
            game.headers[h] = puzzle.game.headers[h]
        game.headers['Result'] = result
        return str(game)
Ejemplo n.º 13
0
 def export(self, pgn_headers=None) -> Game:
     """ pgn_headers - PGN headers to include in the exported PGN
     """
     fen = self.puzzle.initial_board.fen()
     board = chess.Board(fen)
     game = Game().from_board(board)
     game_node = game
     game_node.comment = "score: %s -> %s" % (_score_to_str(
         self.puzzle.initial_score), _score_to_str(self.puzzle.final_score))
     comment = self._candidate_moves_annotations(self.puzzle.analyzed_moves)
     for position in self.puzzle.positions:
         game_node = game_node.add_variation(
             chess.Move.from_uci(position.initial_move.uci()))
         if comment:
             game_node.comment = comment
         comment = self._candidate_moves_annotations(
             position.candidate_moves)
     if pgn_headers:
         for h in pgn_headers:
             if h == "FEN":
                 continue
             game.headers[h] = pgn_headers[h]
     game.headers['PuzzleCategory'] = self.puzzle.category()
     puzzle_winner = self.puzzle.winner()
     if puzzle_winner:
         game.headers['PuzzleWinner'] = puzzle_winner
     game.headers['PuzzleEngine'] = AnalysisEngine.name()
     game.headers['PuzzleMakerVersion'] = __version__
     return game
Ejemplo n.º 14
0
def pgn_game_to_serializable_game(pgn_game: pgn.Game) -> SerializableGame:
    current_index = 1
    all_positions: List[SerializablePosition] = []

    def parse_position(pgn_position: pgn.ChildNode,
                       is_mainline: bool) -> SerializablePosition:
        nonlocal current_index
        nonlocal all_positions
        index = current_index
        current_index += 1
        next_pos_index = None
        if pgn_position.variations:
            next_pos_index = parse_position(pgn_position.variations[0],
                                            True).index
        variations_indexes = []
        if len(pgn_position.variations) > 1:
            variations_indexes = [
                parse_position(p, False).index
                for i, p in enumerate(pgn_position.variations) if i > 0
            ]
        position = SerializablePosition(
            index=index,
            next_position_index=next_pos_index,
            variations_indexes=variations_indexes,
            nags=list(pgn_position.nags),
            fen=pgn_position.board().fen(),
            comment=pgn_position.comment,
            commentBefore=pgn_position.starting_comment,
            san=pgn_position.san(),
            is_mainline=is_mainline,
            move=Move(from_square=square_name(pgn_position.move.from_square),
                      to=square_name(pgn_position.move.to_square),
                      promotion=pgn_position.move.promotion))
        all_positions.insert(0, position)
        return position

    first_pos = SerializablePosition(index=0,
                                     fen=pgn_game.board().fen(),
                                     is_mainline=True,
                                     nags=[],
                                     san="",
                                     variations_indexes=[],
                                     next_position_index=1)
    all_positions.append(first_pos)
    for i, position in enumerate(pgn_game.variations):
        if i != 0:
            first_pos.variations_indexes.append(current_index)
        parse_position(position, i == 0)
    headers: Dict[str, str] = {}
    for key in pgn_game.headers.keys():
        headers[key] = pgn_game.headers[key]
    game = SerializableGame(
        headers=headers,
        comment=pgn_game.starting_comment,
        positions=all_positions,
    )
    return game
Ejemplo n.º 15
0
def advanced_pawn(game: Game) -> bool:
    for node in game.mainline():
        if is_pawn_move(node):
            rank = square_rank(node.move.to_square)
            if rank > 5 and node.turn() == BLACK:
                return True
            if rank < 3 and node.turn() == WHITE:
                return True
    return False
Ejemplo n.º 16
0
    def test_minimax(self):
        board = chess.Board()
        brain = MiniMax(self.umka)
        while not board.is_game_over():
            move = brain.run(board, DEPTH)
            board.push(move)
            print(str(chess.pgn.Game().from_board(board)).split("\n\n")[1])

        game = Game().from_board(board)
        print(game)
Ejemplo n.º 17
0
def configure_pgn(board):
    """Return a PGN representation of a completed chess game."""
    pgn = Game.from_board(board)
    pgn.headers['Event'] = 'Eternal Chess'
    pgn.headers['Site'] = 'www.eternalchess.com'
    pgn.headers['Date'] = datetime.now().strftime(DATE_FORMAT)
    pgn.headers['Round'] = str(int(get_n_of_games()) + 1)
    pgn.headers['White'] = 'Random'
    pgn.headers['Black'] = 'Random'
    return str(pgn)
Ejemplo n.º 18
0
def configure_pgn(board):
    """Return a PGN representation of a completed chess game."""
    pgn = Game.from_board(board)
    pgn.headers['Event'] = 'Eternal Chess'
    pgn.headers['Site'] = 'www.eternalchess.com'
    pgn.headers['Date'] = datetime.now().strftime(DATE_FORMAT)
    pgn.headers['Round'] = str(int(get_n_of_games()) + 1)
    pgn.headers['White'] = 'Random'
    pgn.headers['Black'] = 'Random'
    return str(pgn)
Ejemplo n.º 19
0
def play(brain):
    board = chess.Board()

    while not board.is_game_over():
        move = brain.make_move(board, time_to_think=15 * 100)
        print(move, brain.best_val, brain.best_move, brain.root_moves)
        board.push(move)
        pprint.pprint(str(board))
        print(str(chess.pgn.Game().from_board(board)).split("\n\n")[1])

    game = Game().from_board(board)
    print(game)
Ejemplo n.º 20
0
    def generate_pgn(self, game: Game):
        """
        Gets PGN for given game

        :param game: Current game
        :type game: Game
        :return: Bot message formatted with PGN
        :rtype: str
        """
        chess_game = ChessGame()
        chess_game.headers["White"] = str(game.player1.name)
        chess_game.headers["Black"] = str(game.player2.name)
        chess_game.headers["Result"] = str(game.result)
        last_node = chess_game
        for move in game.board.move_stack:
            last_node = last_node.add_variation(move)

        result = f"```\n{str(chess_game)}\n```"
        if game.id:
            result += f'Game id: `{game.id}`'
        return result
Ejemplo n.º 21
0
def classify(game: Game) -> int:
    """Attempt to classify the opening in a PGN game.

    Args:
        game (chess.pgn.Game): The game to classify.

    Returns:
        int: The ply count of the last book move.
             If no opening is identified, returns 0.
    """
    epds = list(
        enumerate((node.board().epd() for node in game.mainline()), start=0))
    with open("data/eco.tsv") as eco:
        reader = csv.DictReader(eco, delimiter="\t")
        for opening in reader:
            for ply, epd in reversed(epds):
                if epd == opening["fen"]:
                    game.headers["ECO"] = opening["eco"]
                    game.headers["Opening"] = opening["name"]
                    return ply
    return 0
Ejemplo n.º 22
0
def parse_pgn_game(pgn: Game):
    """ Parse a PGN game object and add it and its moves to DB """
    print('Parsing PGN game...')
    game_id = bson.ObjectId()

    def is_int(var: str) -> bool:
        """ Converter for ELO strings """
        try:
            int(var)
        except ValueError:
            return False
        return True
    db_game = {
        '_id': game_id,
        'date': pgn.headers['Date'] if 'Date' in pgn.headers else '???',
        'white': pgn.headers['White'] if 'White' in pgn.headers else '???',
        'white_elo': int(pgn.headers['WhiteElo']) if (
            'WhiteElo' in pgn.headers
            and is_int(pgn.headers['WhiteElo'])) else 0,
        'black': pgn.headers['Black'] if 'Black' in pgn.headers else '???',
        'black_elo': int(pgn.headers['BlackElo']) if (
            'BlackElo' in pgn.headers
            and is_int(pgn.headers['BlackElo'])) else 0,
        'result': pgn.headers['Result'] if 'Result' in pgn.headers else '???'
        }
    if db.games.find_one({k: v for k, v in db_game.items() if k != '_id'}):
        print('SKIPPED!')
        return
    print('Inserting:', db_game)
    db.games.insert_one(db_game)
    white_theory = db_game['white_elo'] >= 2500
    black_theory = db_game['black_elo'] >= 2500
    turn = True
    b = chess.Board()
    for i, move in enumerate(pgn.mainline_moves()):
        san = b.san(move)
        b.push(move)
        db_move = {
            'leads_to': b.fen(),
            'uci': move.uci(),
            'san': san,
            'score_diff': None
            }
        b.pop()  # ugly, but we need the original position
        if (turn and white_theory) or (not turn and black_theory):
            idatabase.insert_board(b.fen(), [db_move], [], game_id if i > 5 else None)
        else:
            idatabase.insert_board(b.fen(), [], [db_move], game_id if i > 5 else None)
        b.push(move)  # so now we put it back
        turn = not turn
        if i > database.MAX_DEPTH:
            break
Ejemplo n.º 23
0
 def reportpgn(self):
     rootboard = self.getrootboard()
     game = Game()
     game.setup(rootboard)
     game.comment = self.rootnode().comment()
     game = self.addmovesrecursive(self.rootnode(), game)
     exporter = StringExporter(headers=True, variations=True, comments=True)
     pgn = game.accept(exporter)
     return pgn
Ejemplo n.º 24
0
def analyze_game(engine: SimpleEngine,
                 game: Game) -> Optional[Tuple[GameNode, List[Move], Kind]]:
    """
    Evaluate the moves in a game looking for puzzles
    """

    game_url = game.headers.get("Site", "?")
    logger.debug("Analyzing game {}...".format(game_url))

    prev_score: Score = Cp(0)

    for node in game.mainline():

        ev = node.eval()

        if not ev:
            logger.debug("Skipping game without eval on move {}".format(
                node.board().fullmove_number))
            return None

        winner = node.board().turn
        score = ev.pov(winner)

        # was the opponent winning until their last move
        if prev_score > Cp(-300) or not is_down_in_material(
                node.board(), winner):
            pass
        elif mate_soon < score < Mate(1):
            logger.info("Mate found on {}#{}. Probing...".format(
                game_url, ply_of(node.board())))
            solution = cook_mate(engine, node, winner)
            if solution is not None:
                return node, solution, Kind("mate")
        elif score > juicy_advantage:
            logger.info("Advantage found on {}#{}. Probing...".format(
                game_url, ply_of(node.board())))
            solution = cook_advantage(engine, node, winner)
            if solution is not None:
                return node, solution, Kind("mate")
        else:
            print(score)

        prev_score = score

    return None
Ejemplo n.º 25
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)
Ejemplo n.º 26
0
    def learn(self, iters=100, c=10):
        """
        Run the Q-learning algorithm. Play greedy on the final iter
        Args:
            iters: int
                amount of games to train
            c: int
                update the network every c games

        Returns: pgn (str)
            pgn string describing final game

        """
        for k in range(iters):
            self.env.reset()
            states, actions, rewards, action_spaces = self.play_game(k)
            self.reinforce_agent(states, actions, rewards, action_spaces)

        pgn = Game.from_board(self.env.board)
        reward_smooth = pd.DataFrame(self.reward_trace)
        reward_smooth.rolling(window=10, min_periods=0).mean().plot()

        return pgn
Ejemplo n.º 27
0
import numpy as np  # linear algebra
import pandas as pd  # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt
import os

from RLC.real_chess import agent, environment, learn, tree
import chess
from chess.pgn import Game

opponent = agent.GreedyAgent()
env = environment.Board(opponent, FEN=None)
player = agent.Agent(lr=0.001, network='big')
player.fix_model()
learner = learn.TD_search(env, player, gamma=0.8, search_time=1.5)
node = tree.Node(learner.env.board, gamma=learner.gamma)

w_before = learner.agent.model.get_weights()
n_iters = 105




print(opponent.predict(np.expand_dims(env.layer_board, axis=0)))
learner.search_time = 60
learner.play_game(n_iters)
pgn = Game.from_board(learner.env.board)
with open("rlc_pgn","w") as log:
    log.write(str(pgn))