Esempio n. 1
0
    def find_path(self):
        """Find a path to the destination.
        
        Destination (PathFinder.destination) has to be set beforehand. This method implements a Breadth First Search algorithm (`Wikipedia <https://en.wikipedia.org/wiki/Breadth-first_search>`_) to find the shortest path to destination.

        Example::
        
            mykillernpc.actuator = PathFinder(game=mygame,actuated_object=mykillernpc)
            mykillernpc.actuator.set_destination( mygame.player.pos[0], mygame.player.pos[1] )
            mykillernpc.actuator.find_path()
        
        .. warning:: PathFinder.destination is a tuple! Please use PathFinder.set_destination(x,y) to avoid problems.

        """
        if self.actuated_object == None:
            raise HacException('actuated_object is not defined','PathFinder.actuated_object has to be defined.')
        if not isinstance(self.actuated_object, Movable):
            raise HacException('actuated_object not a Movable object','PathFinder.actuated_object has to be an instance of a Movable object.')
        if self.destination == None:
            raise HacException('destination is not defined','PathFinder.destination has to be defined.')

        queue = collections.deque([[(self.actuated_object.pos[0],self.actuated_object.pos[1])]]) 
        seen = set([(self.actuated_object.pos[0],self.actuated_object.pos[1])]) 
        while queue: 
            path = queue.popleft() 
            x, y = path[-1] 
            if (x,y) == self.destination: 
                self._current_path = path
                # We return only a copy of the path as we need to keep the real one untouched for our own needs.
                return path.copy() 
            for x2, y2 in ((x+1,y), (x-1,y), (x,y+1), (x,y-1)): 
                if 0 <= y2 < self.game.current_board().size[0] and 0 <= x2 < self.game.current_board().size[1] and self.game.current_board().item(x2,y2).overlappable() and (x2, y2) not in seen: 
                    queue.append(path + [(x2, y2)]) 
                    seen.add((x2, y2))
        return []
Esempio n. 2
0
    def change_level(self, level_number):
        """
        Change the current level, load the board and place the player to the right place.

        Example::

            game.change_level(1)

        :param level_number: the level number to change to.
        :type level_number: int

        :raises HacInvalidTypeException: If parameter is not an int.
        """
        if type(level_number) is int:
            if self.player == None:
                raise HacException(
                    'undefined_player',
                    'Game.player is undefined. We cannot change level without a player. Please set player in your Game object: mygame.player = Player()'
                )
            if level_number in self._boards.keys():
                if self.player.pos[0] != None or self.player.pos[1] != None:
                    self._boards[self.current_level]['board'].clear_cell(
                        self.player.pos[0], self.player.pos[1])
                self.current_level = level_number
                b = self._boards[self.current_level]['board']
                b.place_item(self.player, b.player_starting_position[0],
                             b.player_starting_position[1])
            else:
                raise HacInvalidLevelException(
                    f"Impossible to change level to an unassociated level (level number {level_number} is not associated with any board).\nHave you called:\ngame.add_board({level_number},Board()) ?"
                )
        else:
            raise HacInvalidTypeException(
                'level_number needs to be an int in change_level(level_number).'
            )
Esempio n. 3
0
 def display_menu(self,
                  category,
                  orientation=Constants.ORIENTATION_VERTICAL,
                  paginate=10):
     """
     .. TODO:: Documentation
     """
     line_end = '\n'
     if orientation == Constants.ORIENTATION_HORIZONTAL:
         line_end = ' | '
     if category not in self._menu:
         raise HacException(
             'invalid_menu_category',
             f"The '{category}' category is not registered in the menu. Did you add any menu entry in that category with Game.add_menu_entry('{category}','some shortcut','some message') ? If yes, then you should check for typos."
         )
     pagination_counter = 1
     for k in self._menu[category]:
         if k['shortcut'] == None:
             print(k['message'], end=line_end)
         else:
             print(f"{k['shortcut']} - {k['message']}", end=line_end)
             pagination_counter += 1
             if pagination_counter > paginate:
                 print('')
                 pagination_counter = 1
Esempio n. 4
0
 def __init__(self,
              name="projectile",
              direction=Constants.RIGHT,
              step=1,
              range=5,
              model="\U00002301",
              movement_animation=None,
              hit_animation=None,
              hit_model=None,
              hit_callback=None,
              is_aoe=False,
              aoe_radius=0,
              parent=None,
              *args):
     if range % step != 0:
         raise HacException(
             "incorrect_range_step",
             "range must be a factor of step"
             " in Projectile",
         )
     Movable.__init__(self,
                      model=model,
                      step=step,
                      name=name,
                      parent=parent)
     self.direction = direction
     self.range = range
     self.movement_animation = movement_animation
     self._directional_animations = {}
     self._directional_models = {}
     self.hit_animation = hit_animation
     self.hit_model = hit_model
     self.hit_callback = hit_callback
     self.callback_parameters = args
     self.actuator = UnidirectionalActuator(direction=direction)
     self.is_aoe = is_aoe
     self.aoe_radius = aoe_radius
     self.parent = parent
Esempio n. 5
0
    def check_sanity(self):
        """Check the board sanity.

        This is essentially an internal method called by the constructor.
        """
        sanity_check = 0
        if type(self.size) is list:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO', ("The 'size' parameter must"
                                                   " be a list."))
        if len(self.size) == 2:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The 'size' parameter must"
                                " be a list of 2 elements."))
        if type(self.size[0]) is int:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The first element of the "
                                "'size' list must be an integer."))
        if type(self.size[1]) is int:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The second element of the 'size' "
                                "list must be an integer."))
        if type(self.name) is str:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               "The 'name' parameter must be a string.")
        if type(self.ui_border_bottom) is str:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The 'ui_border_bottom' parameter "
                                "must be a string."))
        if type(self.ui_border_top) is str:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The 'ui_border_top' parameter must "
                                "be a string."))
        if type(self.ui_border_left) is str:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The 'ui_border_left' parameter must "
                                "be a string."))
        if type(self.ui_border_right) is str:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The 'ui_border_right' parameter must "
                                "be a string."))
        if type(self.ui_board_void_cell) is str:
            sanity_check += 1
        else:
            raise HacException('SANITY_CHECK_KO',
                               ("The 'ui_board_void_cell' parameter must "
                                "be a string."))

        if self.size[0] > 80:
            warn((f"The first dimension of your board is {self.size[0]}. "
                  "It is a good practice to keep it at a maximum of 80 for "
                  "compatibility with older terminals."))

        if self.size[1] > 80:
            warn((f"The second dimension of your board is {self.size[1]}. "
                  "It is a good practice to keep it at a maximum of 80 for "
                  "compatibility with older terminals."))

        # If all sanity check clears return True else raise a general error.
        # I have no idea how the general error could ever occur but...
        # better safe than sorry!
        if sanity_check == 10:
            return True
        else:
            raise HacException('SANITY_CHECK_KO',
                               "The board data are not valid.")