예제 #1
0
    def __init__(self, size=(6, 6), initial_tiles=4, goal_value=13, min_group=2,
                 animation=True):
        """Constructor

        Parameters:
            size (tuple<int, int>): The number of (rows, columns) in the game.
            initial_tiles (int): The number of tiles.
            goal_value (int): The value of the goal tile.
            min_group (int): The minimum number of tiles required for a
                             connected group to be joinable.
            animation (bool): If True, animation will be enabled.

        """
        self.goal_value = goal_value

        self.initial_tiles = initial_tiles

        self._selector = WeightedSelector({1: 1})
        self.reset()

        generator = tile_generators.WeightedGenerator(self._selector, self._construct_tile)

        super().__init__(size=size, min_group=min_group, animation=animation)

        rows, columns = size
        self.grid = model.LoloGrid(generator, rows=rows, columns=columns,
                                   animation=animation)
        self.grid.fill()
        self.generator = generator

        self._score = max(tile.get_value() for _, tile in self.grid.items())
예제 #2
0
    def __init__(self,
                 size=(6, 6),
                 types=3,
                 min_group=3,
                 max_tile_value=50,
                 max_tile_type='max',
                 normal_weight=20,
                 max_weight=2,
                 animation=True,
                 autofill=True):
        """Constructor

        Parameters:
            size (tuple<int, int>): The number of (rows, columns) in the game.
            types (int): The number of types of basic tiles.
            min_group (int): The minimum number of tiles required for a
                             connected group to be joinable.
            normal_weight (int): The relative weighted probability that a basic
                                 tile will be generated.
            max_weight (int): The relative weighted probability that a maximum
                              tile will be generated.
            animation (bool): If True, animation will be enabled.
            autofill (bool): Automatically fills the grid iff True.
        """

        # Basic properties
        self.max_tile_value = max_tile_value
        self.max_tile_type = max_tile_type
        self.types = types
        self._max_unlocked = False

        # Tile probabilities
        self.normal_likelihood = normal_weight
        self.max_likelihood = max_weight

        weighted_types = {i: normal_weight for i in range(1, types + 1)}
        self._selector = WeightedSelector(weighted_types)

        generator = tile_generators.WeightedGenerator(self._selector,
                                                      self._construct_tile)

        super().__init__(size,
                         generator,
                         min_group,
                         animation=animation,
                         autofill=autofill)
예제 #3
0
    def __init__(self,
                 dot_weights,
                 kinds=(1, 2, 3),
                 size=(6, 6),
                 dead_cells=None,
                 objectives: ObjectiveManager = None,
                 min_group=2,
                 moves=20,
                 animation=True):
        """Constructor

        Parameters:
            dot_weights (dict<class, float>): The weighting for picking the
                                              class of dot to initiate
            kinds (set<int|str>): All possible kinds that a dot could be
            size (tuple<int, int>): The number of (rows, columns) in the game
            dead_cells (set<tuple<int, int>>): Set of cells that are disabled (i.e. VoidCells)
            objectives (ObjectiveManager): Objectives for the game
            min_group (int): The minimum number of dots required for a
                             connected group to be joinable
            moves (int): The number of moves allowed before game over
            animation (bool): If True, animation will be enabled
        """
        # Tile probabilities
        self.kind_selector = WeightedSelector.from_equals(set(kinds))

        dot_selector = WeightedSelector(dot_weights)
        dot_factory = DotFactory(self.kind_selector, dot_selector)

        super().__init__(dot_factory,
                         size=size,
                         dead_cells=dead_cells,
                         objectives=objectives,
                         min_group=min_group,
                         moves=moves,
                         animation=animation)
예제 #4
0
class RegularGame(model.AbstractGame):
    """Regular game of Lolo.

    Join groups of three or more until max tiles are formed. Join max tiles to
    destroy all surrounding tiles."""

    GAME_NAME = "Regular"

    def __init__(self,
                 size=(6, 6),
                 types=3,
                 min_group=3,
                 max_tile_value=50,
                 max_tile_type='max',
                 normal_weight=20,
                 max_weight=2,
                 animation=True,
                 autofill=True):
        """Constructor

        Parameters:
            size (tuple<int, int>): The number of (rows, columns) in the game.
            types (int): The number of types of basic tiles.
            min_group (int): The minimum number of tiles required for a
                             connected group to be joinable.
            normal_weight (int): The relative weighted probability that a basic
                                 tile will be generated.
            max_weight (int): The relative weighted probability that a maximum
                              tile will be generated.
            animation (bool): If True, animation will be enabled.
            autofill (bool): Automatically fills the grid iff True.
        """

        # Basic properties
        self.max_tile_value = max_tile_value
        self.max_tile_type = max_tile_type
        self.types = types
        self._max_unlocked = False

        # Tile probabilities
        self.normal_likelihood = normal_weight
        self.max_likelihood = max_weight

        weighted_types = {i: normal_weight for i in range(1, types + 1)}
        self._selector = WeightedSelector(weighted_types)

        generator = tile_generators.WeightedGenerator(self._selector,
                                                      self._construct_tile)

        super().__init__(size,
                         generator,
                         min_group,
                         animation=animation,
                         autofill=autofill)

    def get_default_score(self):
        """(int) Returns the default score."""
        return 0

    def reset(self):
        """Resets the game."""
        super().reset()

        self._lock_max()

    def _construct_tile(self, type, position, *args, **kwargs):
        """(RegularTile) Returns a new tile from the generator's selection.

        Parameters:
            type (*): The type of the tile.
            position (tuple<int, int>): The position the tile will initially exist in. Unused.
            *args: Extra positional arguments for the tile.
            **kwargs: Extra keyword arguments for the tile.
        """
        return RegularTile(type,
                           *args,
                           max_value=self.max_tile_value,
                           **kwargs)

    def _check_unlock_max(self, current):
        """Unlocks the max tile if the current tile is a max tile.

        Parameters:
            current (RegularTile): The current tile.
        """
        if not self._max_unlocked and current.is_max():
            self._selector.update({self.max_tile_type: self.max_likelihood})
            self._max_unlocked = True

    def _lock_max(self):
        """Locks max tile."""
        del self._selector[self.max_tile_type]
        self._max_unlocked = False

    def update_score_on_activate(self, current, connected):
        """Updates the score based upon the current tile & connected tiles that
        were joined to it.

        Parameter:
            current (RegularTile): The tile recently current to.
            connected (tuple<RegularTiles>): The tiles that were joined to
                                              current.
        """
        factor = 50 if current.is_combo_max() else 1
        points = (len(connected) + 1) * factor
        self.set_score(self.get_score() + points)

    def activate(self, position):
        """Attempts to activate the tile at the given position.

        Parameters:
            position (tuple<int, int>): The position to activate.

        Yield:
            Yields None for each frame of drops and "DONE" when the dropping
            has finished.
        """
        connected_cells = self._attempt_activate_collect(position)
        connected_cells.remove(position)

        self._resolving = True

        current = self.grid[position]
        connected_tiles = [self.grid[cell] for cell in connected_cells]

        # Join tiles
        current.join(connected_tiles)

        self.update_score_on_activate(current, connected_tiles)

        self._check_unlock_max(current)

        for cell in connected_cells:
            del self.grid[cell]

        yield from self.grid.replace_blanks()

        # Find tile, in case it moved.
        # Hack, but it works. Ideally above logic would indicate movement.
        position = self.find_tile_position(current)

        # Perform combo
        yield from self._explode_combo(position)

        # Final step
        yield "DONE"

        self._resolving = False
        self.emit('resolve')

        # Check for game over.
        if self.game_over():
            self.emit('game_over')

    def remove(self, *positions):
        """Attempts to remove the tiles at the given positions.

        Parameters:
            *positions (tuple<int, int>): The position to activate.

        Yield:
            Yields None for each frame of drops and "DONE" when the dropping
            has finished.
        """

        self._resolving = True

        connected_cells = positions
        connected_tiles = [self.grid[cell] for cell in connected_cells]

        for cell in connected_cells:
            del self.grid[cell]

        yield from self.grid.replace_blanks()

        # Final step
        yield "DONE"

        self._resolving = False
        self.emit('resolve')

        # Check for game over.
        if self.game_over():
            self.emit('game_over')

    def find_tile_position(self, tile):
        """(tuple<int, int>) Returns the row, column position of the tile if it
        exists in the game grid, else None."""
        for position, a_tile in self.grid.items():
            if a_tile is tile:
                return position

        return None

    def _explode_combo(self, position):
        """Internal helper method to check if the tile at a position is a
        combination maximum. If so, explodes it, deleting the tile and all
        surrounding tiles.

        Parameters:
            position (tuple<int, int>): Row, column position of the tile.
        """
        current = self.grid[position]

        if current.is_combo_max():
            yield "REMOVE"

            exploded_cells = self.grid.get_adjacent_cells(
                position, deltas=matrix.RADIAL_DELTAS)

            del self.grid[position]

            for cell in exploded_cells:
                tile = self.grid[cell]
                if tile is None or not tile.get_disabled():
                    del self.grid[cell]

            self.set_score(self.get_score() + current.get_value())

            yield from self.grid.replace_blanks()
예제 #5
0
class Make13Game(game_regular.RegularGame):
    """Make13 Lolo game.

    Groups of two or more can be combined to increase tile's value by one.

    Game is won when a 13 is made.
    """

    def __init__(self, size=(6, 6), initial_tiles=4, goal_value=13, min_group=2,
                 animation=True):
        """Constructor

        Parameters:
            size (tuple<int, int>): The number of (rows, columns) in the game.
            initial_tiles (int): The number of tiles.
            goal_value (int): The value of the goal tile.
            min_group (int): The minimum number of tiles required for a
                             connected group to be joinable.
            animation (bool): If True, animation will be enabled.

        """
        self.goal_value = goal_value

        self.initial_tiles = initial_tiles

        self._selector = WeightedSelector({1: 1})
        self.reset()

        generator = tile_generators.WeightedGenerator(self._selector, self._construct_tile)

        super().__init__(size=size, min_group=min_group, animation=animation)

        rows, columns = size
        self.grid = model.LoloGrid(generator, rows=rows, columns=columns,
                                   animation=animation)
        self.grid.fill()
        self.generator = generator

        self._score = max(tile.get_value() for _, tile in self.grid.items())

    def reset(self):
        # super().reset()
        weights = {i: self.get_tile_weight(i) for i in
                   range(1, self.initial_tiles + 1)}
        self._selector.update(weights, clear=True)

    def get_tile_weight(self, value):
        return 2 ** (self.goal_value - value)

    def _construct_tile(self, type, position):
        """(LevelTile) Returns a randomly generated tile."""
        return LevelTile(type)

    def update_score_on_activate(self, current, connections):
        if current.get_value() > self._score:
            # Update score
            score = current.get_value()
            self._score = score

            # Unlock new tile
            self._selector[score] = self.get_tile_weight(score)

            self.increase_score(score)

        if current.get_value() == self.goal_value:
            self.emit('game_over')
예제 #6
0
class Make13Game(game_regular.RegularGame):
    """Make13 Lolo game.

    Groups of two or more can be combined to increase tile's value by one.

    Game is won when a 13 is made.
    """

    GAME_NAME = "Make 13"

    def __init__(self,
                 size=(6, 6),
                 initial_tiles=4,
                 goal_value=13,
                 min_group=2,
                 animation=True,
                 autofill=True):
        """Constructor

        Parameters:
            size (tuple<int, int>): The number of (rows, columns) in the game.
            initial_tiles (int): The number of tiles.
            goal_value (int): The value of the goal tile.
            min_group (int): The minimum number of tiles required for a
                             connected group to be joinable.
            animation (bool): If True, animation will be enabled.
            autofill (bool): Automatically fills the grid iff True.

        """
        self.goal_value = goal_value

        self.initial_tiles = initial_tiles

        super().__init__(size=size,
                         min_group=min_group,
                         animation=animation,
                         autofill=False)

        self._selector = WeightedSelector({1: 1})
        self.reset()

        generator = tile_generators.WeightedGenerator(self._selector,
                                                      self._construct_tile)

        rows, columns = size
        self.grid = model.LoloGrid(generator,
                                   rows=rows,
                                   columns=columns,
                                   animation=animation)
        if autofill:
            self.grid.fill()
            self._score = self.get_default_score()

        self.generator = generator

    def get_default_score(self):
        """(int) Returns the default score."""
        return max(tile.get_value() for _, tile in self.grid.items())

    def reset(self):
        """Resets the game."""
        weights = {
            i: self.get_tile_weight(i)
            for i in range(1, self.initial_tiles + 1)
        }
        self._selector.update(weights, clear=True)
        super().reset()

    def get_tile_weight(self, value):
        """(float) Returns the weighting for a tile of given value."""
        return 2**(self.goal_value - value)

    def _construct_tile(self, type, position, *args, **kwargs):
        """(LevelTile) Returns a new tile from the generator's selection.

        Parameters:
            type (*): The type of the tile.
            position (tuple<int, int>): The position the tile will initially exist in. Unused.
            *args: Extra positional arguments for the tile.
            **kwargs: Extra keyword arguments for the tile.
        """

        # TODO: remove when serialize is implemented properly
        args = args[1:]

        return LevelTile(type, *args, **kwargs)

    def update_score_on_activate(self, current, connections):
        """Updates the score based upon the current tile & connected tiles that
        were joined to it.

        Parameter:
            current (AbstractTile): The tile recently current to.
            connected (tuple<AbstractTiles>): The tiles that were joined to
                                              current.
        """
        if current.get_value() > self._score:
            # Update score
            score = current.get_value()
            self._score = score

            # Unlock new tile
            self._selector[score] = self.get_tile_weight(score)

            self.set_score(score)

        if current.get_value() == self.goal_value:
            self.emit('game_over')