예제 #1
0
    def parse_move(self, move_list, line):
        m = re.match(self.move_regex, line)
        if m is not None:
            pos = parse_position(self.board_size, m.group(1))
            visits = int(m.group(2))
            winrate = self.flip_winrate(str_to_percent(m.group(3)))
            mc_winrate = self.flip_winrate(str_to_percent(m.group(4)))
            nn_winrate = self.flip_winrate(str_to_percent(m.group(5)))
            nn_count = int(m.group(6))
            policy_prob = str_to_percent(m.group(7))
            pv = [parse_position(self.board_size, p) for p in m.group(8).split()]

            info = {
                'pos': pos,
                'visits': visits,
                'winrate': winrate,
                'mc_winrate': mc_winrate,
                'nn_winrate': nn_winrate,
                'nn_count': nn_count,
                'policy_prob': policy_prob,
                'pv': pv,
                'color': self.whose_turn()
            }
            move_list.append(info)

        m = re.match(self.move_regex_no_vn, line)
        if m is not None:
            pos = parse_position(self.board_size, m.group(1))
            visits = int(m.group(2))
            mc_winrate = self.flip_winrate(str_to_percent(m.group(3)))
            r_winrate = self.flip_winrate(str_to_percent(m.group(4)))
            r_count = int(m.group(5))
            policy_prob = str_to_percent(m.group(6))
            pv = m.group(7)
            pv = [parse_position(self.board_size, p) for p in pv.split()]

            info = {
                'pos': pos,
                'visits': visits,
                'winrate': mc_winrate,
                'mc_winrate': mc_winrate,
                'r_winrate': r_winrate,
                'r_count': r_count,
                'policy_prob': policy_prob,
                'pv': pv,
                'color': self.whose_turn()
            }
            move_list.append(info)
        return move_list
예제 #2
0
    def parse_status_update(self, message):
        """
        Parse number of visits, winrate and PV sequence
        :param message:
        :return: dictionary
        """
        m = re.match(update_regex, message)

        # For non-neural-network
        if m is None:
            m = re.match(update_regex_no_vn, message)

        if m is not None:
            visits = int(m.group(1))
            winrate = self.to_fraction(m.group(2))
            seq = m.group(3)
            seq = [
                utils.parse_position(self.board_size, p) for p in seq.split()
            ]

            return {'visits': visits, 'winrate': winrate, 'seq': seq}
        return {}
예제 #3
0
 def parse_finished(self, stats, stdout):
     m = re.search(self.finished_regex, "".join(stdout))
     if m is not None:
         stats['chosen'] = "resign" if m.group(1) == "resign" else parse_position(self.board_size, m.group(1))
     return stats
예제 #4
0
 def parse_best(self, stats, line):
     m = re.match(self.best_regex, line)
     if m is not None:
         stats['best'] = parse_position(self.board_size, m.group(3).split()[0])
         stats['winrate'] = self.flip_winrate(str_to_percent(m.group(2)))
     return stats
예제 #5
0
    def parse(self, stdout, stderr):
        """
        Parse Leela stdout & stderr
        :param stdout: string
        :param stderr: string
        :return: stats, move_list
        """
        if self.verbosity > 2:
            print("LEELA STDOUT:\n" + "".join(stdout) + "\END OF LEELA STDOUT",
                  file=sys.stderr)
            print("LEELA STDERR:\n" + "".join(stderr) + "\END OF LEELA STDERR",
                  file=sys.stderr)

        stats = {}
        move_list = []

        def flip_winrate(wr):
            return (1.0 - wr) if self.whose_turn() == "white" else wr

        # function filter given list of moves by criteria or win-rate and visits
        def filter_redundant_moves(move_list, stats):

            best_move_visits = stats['visits']
            best_move_winrate = stats['winrate']

            return list(
                filter(
                    lambda move:
                    (best_move_winrate - move['winrate']) < 0.1 and
                    (best_move_visits / move['visits']) < 20, move_list))

        finished = False
        summarized = False
        for line in stderr:
            line = line.strip()
            if line.startswith('================'):
                finished = True

            # Find bookmove string
            m = re.match(bookmove_regex, line)
            if m is not None:
                stats['bookmoves'] = int(m.group(1))
                stats['positions'] = int(m.group(2))

            # Find status string
            m = re.match(status_regex, line)
            if m is not None:
                stats['mc_winrate'] = flip_winrate(float(m.group(1)))
                stats['nn_winrate'] = flip_winrate(float(m.group(2)))
                stats['margin'] = m.group(3)

            m = re.match(status_regex_no_vn, line)
            if m is not None:
                stats['mc_winrate'] = flip_winrate(float(m.group(1)))
                stats['margin'] = m.group(2)

            # Find move string
            m = re.match(move_regex, line)
            if m is not None:
                pos = utils.parse_position(self.board_size, m.group(1))
                visits = int(m.group(2))
                winrate = flip_winrate(self.to_fraction(m.group(3)))
                mc_winrate = flip_winrate(self.to_fraction(m.group(4)))
                nn_winrate = flip_winrate(self.to_fraction(m.group(5)))
                nn_count = int(m.group(6))
                policy_prob = self.to_fraction(m.group(7))
                pv = [
                    utils.parse_position(self.board_size, p)
                    for p in m.group(8).split()
                ]

                info = {
                    'pos': pos,
                    'visits': visits,
                    'winrate': winrate,
                    'mc_winrate': mc_winrate,
                    'nn_winrate': nn_winrate,
                    'nn_count': nn_count,
                    'policy_prob': policy_prob,
                    'pv': pv,
                    'color': self.whose_turn()
                }
                move_list.append(info)

            m = re.match(move_regex_no_vn, line)
            if m is not None:
                pos = utils.parse_position(self.board_size, m.group(1))
                visits = int(m.group(2))
                mc_winrate = flip_winrate(self.to_fraction(m.group(3)))
                r_winrate = flip_winrate(self.to_fraction(m.group(4)))
                r_count = int(m.group(5))
                policy_prob = self.to_fraction(m.group(6))
                pv = m.group(7)
                pv = [
                    utils.parse_position(self.board_size, p)
                    for p in pv.split()
                ]

                info = {
                    'pos': pos,
                    'visits': visits,
                    'winrate': mc_winrate,
                    'mc_winrate': mc_winrate,
                    'r_winrate': r_winrate,
                    'r_count': r_count,
                    'policy_prob': policy_prob,
                    'pv': pv,
                    'color': self.whose_turn()
                }
                move_list.append(info)

            if finished and not summarized:
                m = re.match(best_regex, line)

                # Parse best move and its winrate
                if m is not None:
                    stats['best'] = utils.parse_position(
                        self.board_size,
                        m.group(3).split()[0])
                    stats['winrate'] = flip_winrate(
                        self.to_fraction(m.group(2)))

                # Parse number of visits to stats
                m = re.match(stats_regex, line)
                if m is not None:
                    stats['visits'] = int(m.group(1))
                    summarized = True

        # Find finished string
        m = re.search(finished_regex, "".join(stdout))

        # Add chosen move to stats
        if m is not None:
            stats['chosen'] = "resign" if m.group(
                1) == "resign" else utils.parse_position(
                    self.board_size, m.group(1))

        # Add book move to move list
        if 'bookmoves' in stats and len(move_list) == 0:
            move_list.append({'pos': stats['chosen'], 'is_book': True})
        else:
            required_keys = [
                'mc_winrate', 'margin', 'best', 'winrate', 'visits'
            ]

            # Check for missed data
            for k in required_keys:
                if k not in stats:
                    print("WARNING: analysis stats missing %s data" % k,
                          file=sys.stderr)

            move_list = sorted(
                move_list,
                key=(lambda key: 1000000000000000
                     if info['pos'] == stats['best'] else info['visits']),
                reverse=True)
            move_list = [
                info for (i, info) in enumerate(move_list)
                if i == 0 or info['visits'] > 0
            ]

            move_list = filter_redundant_moves(move_list, stats)

            # In the case where Leela resigns, just replace with the move Leela did think was best
            if stats['chosen'] == "resign":
                stats['chosen'] = stats['best']

        return stats, move_list