def test_update_rank(level, offset, expected, problems_dir):
    """Check whether updating the rank works correctly."""
    p = Problems(problems_dir)
    p.level = level
    p.offset = offset
    p.update_rank()
    assert expected == (p.level, p.offset)
Esempio n. 2
0
    def load_problems(self, problems_dir, rank=None):
        """Load all problems found in the given directory.

        :param str problems_dir: where to look for tsumego
        :param str rank: the current rank of the user.
        """
        if not rank and self.problems:
            rank = self.problems.pretty_rank
        self.problems = Problems(problems_dir, rank)
def test_get_problems(problem_files, problems_dir):
    """Check whether problem files are correctly found and returned."""
    p = Problems(problem_files)
    problems = [
        p._parse_problem(problems_dir / ('%d_kyu_%d.sgf' % (i, i)))
        for i in xrange(20)
    ]
    problems += [
        p._parse_problem(
            problems_dir / ('[%d]%d_kyu_%d.sgf' % (i - 10, i, i + 20))
        ) for i in xrange(20)
    ]
    for i in xrange(20):
        problem = {'rank': None}
        problem.update(p._parse_problem(problems_dir / ('%d.sgf' % i)))
        problems.append(problem)

    assert sorted(p._get_problems(problem_files)) == sorted(problems)
Esempio n. 4
0
class GobanGrid(Grid, Goban):

    """A grid that handles a goban."""

    def __init__(self, *args, **kwargs):
        """init this grid."""
        self.comments_box = None
        self.load_problems(
            problems_dir=kwargs.pop(
                'problems_dir', addon.getSetting('problems_dir')),
            rank=kwargs.pop('rank', addon.getSetting('rank')),
        )
        super(GobanGrid, self).__init__(*args, **kwargs)

    def load_problems(self, problems_dir, rank=None):
        """Load all problems found in the given directory.

        :param str problems_dir: where to look for tsumego
        :param str rank: the current rank of the user.
        """
        if not rank and self.problems:
            rank = self.problems.pretty_rank
        self.problems = Problems(problems_dir, rank)

    def setup_labels(self):
        """Set up all status messages and the comments box."""
        window = self.window
        self.current_rank = window.getControl(ControlIds.rank)
        self.rating_box = window.getControl(ControlIds.rating)
        self.comments_box = window.getControl(ControlIds.comments)
        self.error_control = window.getControl(ControlIds.error)
        self.success_control = window.getControl(ControlIds.success)
        self.success_control.setLabel(_('solved'))
        self.error_control.setLabel(_('off_path'))

        self.update_comment()
        self.update_messages()

    @property
    def labels(self):
        """Get the labels of the current node from the board.

        The labels are white by default, so change the colour of any text to
        black if it was to be displayed on a white stone.
        """
        for (x, y), label in Goban.labels.fget(self):
            if self.board.board[x][y] == 'w':
                label = '[COLOR black]%s[/COLOR]' % label
            yield ((x, y), label)

    def new_tile(self, x, y):
        """Add a new stone.

        :param int x: the column in which this stone is
        :param int y: the row that the stone is in
        """
        stone = Stone(x, y, self, self.tile_width, self.tile_height)
        if self.board:
            stone.set_marker(self.board.board[x][y])
        return stone

    def refresh_board(self):
        """Refresh the contents of the grid."""
        if not self.grid:
            log('No grid found during board refresh', log.LOGDEBUG)
            return

        self.position_marker.setImage(
            get_image("shadow_%s.png" % self.next_player_name))
        self.update_messages()
        self.update_labels()
        self.update_comment()

        # refresh all points
        for x in xrange(self.game.get_size()):
            for y in xrange(self.game.get_size()):
                pos = (x, y)
                if pos in self.marks:
                    self.grid[x][y].mark('mark')
                elif pos in self.triangles:
                    self.grid[x][y].mark('triangle')
                elif pos in self.squares:
                    self.grid[x][y].mark('square')
                elif pos in self.circles:
                    self.grid[x][y].mark('circle')
                elif pos in self.marks:
                    self.grid[x][y].mark('mark')
                else:
                    self.grid[x][y].mark()
                self.grid[x][y].set_player(self.board.board[x][y])
        self.mark_hints()

    def set_size(self, size):
        """Set the board size and refresh what is displayed."""
        if size <= 9:
            actual_size = 9
            if self.rows > 9:
                self.window.getControl(ControlIds.goban).setImage('goban9.png')
        elif 9 < size <= 13:
            actual_size = 13
            if 9 <= self.rows or self.rows > 13:
                self.window.getControl(ControlIds.goban).setImage('goban13.png')
        elif size > 13:
            actual_size = 19
            if 13 <= self.rows:
                self.window.getControl(ControlIds.goban).setImage('goban19.png')

        super(GobanGrid, self).set_size(actual_size)
        # if the board is irregular (i.e. not 9x9, 13x13 or 19x19), make sure
        # that the pointer is correctly set, and that any tiles outside the
        # boundaries are correctly hidden
        if size < actual_size:
            self.rows = size
            self.columns = size
            current_x = self.current.x if self.current.x < size else size - 1
            current_y = self.current.y if self.current.y < size else size - 1
            self.select(self.grid[current_x][current_y])
            # hide all tiles that shouldn't be shown
            for p1 in xrange(0, actual_size):
                for p2 in xrange(size, actual_size):
                    self.grid[p1][p2].set_marker('wall')
                    self.grid[p2][p1].set_marker('wall')

    def load(self, sgf=None):
        """Load the given SGF, or reload the current one if none provided.

        :param (str or None) sgf: the SGF to be loaded
        """
        super(Grid, self).load(sgf)
        if self.game:
            self.reset()
            self.set_size(self.game.get_size())
            self.refresh_board()

    def next(self):
        """Load the next problem.

        If no problem can be loaded, an error message is displayed.
        """
        # loop over problems until a good one is found
        for problem in self.problems:
            self.problem = problem
            try:
                self.load(self.problem['sgf'])
            except (ValueError, IndexError):
                traceback.print_exc()
            else:
                self.current_rank.setText(
                    _('current_rank') % self.problems.rank)
                if self.problem.get('rank'):
                    rating = self.problem.get('rating') or 0
                    rank_value, rank = self.problem.get('rank')
                    self.rating_box.setText(
                        _('rating') % (rating, rank_value, rank))
                else:
                    self.rating_box.setText('')
                return
        else:
            level = self.problems.level
            ranks = map(
                lambda rank: '%d %s' % rank,
                map(self.problems.get_rank, [level + 3, level - 3])
            )
            self.comments_box.setText(_('no_problems_found') % tuple(ranks))

    def reset(self):
        """Reset the board."""
        self.hints = False
        self.position_marker.setImage(
        get_image("shadow_%s.png" % self.next_player_name))
        self.update_messages()
        self.update_labels()

    def problem_solved(self, solved, weight=0.25):
        """Mark whether this problem was solved or not.

        :param boolean solved: whether the problem was solved
        :param float weight: the wieght of the solution.
        """
        if 'solved' in self.problem:
            return

        if solved:
            self.problems.success(self.problem['rank'], weight)
        else:
            self.problems.failure(self.problem['rank'], weight)
        self.problem['solved'] = solved
        addon.setSetting('level', self.problems.pretty_rank)

    def toggle_hints(self, state=None):
        """Toggle the display of hints on the board.

        :param boolean state: this can be used to force the state
        :returns: whether or not hints are shown
        """
        self.problem_solved(False, 0.4)
        self.hints = state if state is not None else not self.hints
        self.refresh_board()
        return self.hints

    def update_comment(self, comment=None):
        """Set the comment to the given comment, or the current SGF comment.

        If no comment is provided, the comment of the current SGF node will
        be displayed.

        :param str or None comment: the comment to be displayed
        """
        if not self.comments_box:
            log('No comments box found during comment refresh', log.LOGDEBUG)
            return

        if comment is None:
            comment = self.current_comment.replace('FORCE', '').replace('RIGHT', '')  # noqa
        self.comments_box.setText(comment)

    def update_messages(self):
        """Update the status messages' visibility."""
        self.error_control.setVisible(bool(self.board and not self.on_path))
        self.success_control.setVisible(bool(self.board and self.correct))

    def mark_hints(self):
        """Mark all hints on the board."""
        if not self.hints:
            return

        def mark_node(node, mark=None):
            """Mark a single hint on the board.

            :param str mark: what the marker should be
            """
            _, (x, y) = node.get_move()
            self.grid[x][y].set_marker(mark)

        # get rid of any previous markers - the grandparent must be used,
        # because the parent is automatically placed and has no hints
        if self.node.parent and self.node.parent.parent:
            for node in filter(lambda v: v != self.node, self.node.parent.parent):
                _, (x, y) = node.get_move()
                self.grid[x][y].set_image()

        for child in self.node:
            mark_node(child, 'good' if self.correct_path(child) else 'bad')

    def handle_key(self, key):
        """Handle the given key.

        :param int key: the key code
        :returns: whether the action was handled
        """
        if not self.board:
            return
        if key in SELECT:
            self.move(*self.current.pos)
            self.random_move()
            if self.correct:
                self.problem_solved(True)
        elif key in BACK:
            self.problem_solved(False)
            if not self.correct and self.on_path:
                self.back()
            self.back()
        elif key in hoshi:
            x, y = hoshi[key]
            self.current = self.grid[x][y]
            self.position_marker.setPosition(*self.current.display_pos)
        else:
            return False
        self.refresh_board()
        return True
def test_parse_rank(rank_str, rank, problems_dir):
    """Test whether rank strings are correctly parsed."""
    p = Problems(problems_dir)
    assert p._parse_level(rank_str) == rank
def test_invalid_parse_problem(filename, problems_dir):
    """Check whether invalid names return None."""
    p = Problems(problems_dir)
    assert p._parse_problem(filename) is None
def test_unparsable_parse_problem(filename, problems_dir):
    """Check whether names that cannot be parsed only return the filename."""
    p = Problems(problems_dir)
    assert p._parse_problem(filename) == {'problem_file': filename}
def test_parse_problem(filename, result, problems_dir):
    """Test whether filenames get parsed correctly."""
    p = Problems(problems_dir)
    result['problem_file'] = filename
    assert p._parse_problem(filename) == result
def test_rank(level, rank, problems_dir):
    """Check whether the rank is correctly calculated."""
    p = Problems(problems_dir)
    p.level = level
    assert p.rank == rank == p.get_rank(level)
    assert p.pretty_rank == '%d %s' % rank