0

I was asked to write a method to move entity form one position to another using dictionary under the grid class with some conditions:

  1. If the end position or start position is out of the grid bounds, do not attempt to move.
  2. If there is no entity at the given start position, do not attempt to move.
  3. If there is an entity at the given end position, replace that entity with the entity from the start position.

The start position should not have an entity after moving. start: The position the entity is in initially. end: The position to which the entity will be moved.

Code given:

    from typing import Tuple, Optional, Dict, List

class Position:
    """
    The position class represents a location in a 2D grid.

    A position is made up of an x coordinate and a y coordinate.
    The x and y coordinates are assumed to be non-negative whole numbers which
    represent a square in a 2D grid.

    Examples:
        >>> position = Position(2, 4)
        >>> position
        Position(2, 4)
        >>> position.get_x()
        2
        >>> position.get_y()
        4
    """

    def __init__(self, x: int, y: int):
        """
        The position class is constructed from the x and y coordinate which the
        position represents.

        Parameters:
            x: The x coordinate of the position
            y: The y coordinate of the position

        Precondition:
            x >= 0 and y >= 0
        """
        self._x = x
        self._y = y

    def get_x(self) -> int:
        """Returns the x coordinate of the position."""
        return self._x

    def get_y(self) -> int:
        """Returns the y coordinate of the position."""
        return self._y

    def distance(self, position: "Position") -> int:
        """
        Returns the manhattan distance between this point and another point.

        The manhattan distance for two points (x_1, y_1) and (x_2, y_2)
        is calculated with the formula

        |x_1 - x_2| + |y_1 - y_2|

        where |x| is the absolute value of x.

        Parameters:
            position: Another position to calculate the distance from
                      the current position.
        """
        dx = abs(self.get_x() - position.get_x())
        dy = abs(self.get_y() - position.get_y())
        return dx + dy

    def in_range(self, position: "Position", range: int) -> bool:
        """
        Returns true if the given position is in range of the current position.

        The distance between the two positions are calculated by the manhattan
        distance. See the Position.distance method for details.

        Parameters:
            position: Another position to check if it is within range
                      of this current position.
            range: The maximum distance for another position to be considered
                   within range of this position.

        Precondition:
            range >= 0
        """
        distance = self.distance(position)
        return distance < range

    def add(self, position: "Position") -> "Position":
        """
        Add a given position to this position and return a new instance of
        Position that represents the cumulative location.

        This method shouldn't modify the current position.

        Examples:
            >>> start = Position(1, 2)
            >>> offset = Position(2, 1)
            >>> end = start.add(offset)
            >>> end
            Position(3, 3)

        Parameters:
            position: Another position to add with this position.

        Returns:
            A new position representing the current position plus
            the given position.
        """
        return Position(self._x + position.get_x(), self._y + position.get_y())

    def __eq__(self, other: object) -> bool:
        """
        Return whether the given other object is equal to this position.

        If the other object is not a Position instance, returns False.
        If the other object is a Position instance and the
        x and y coordinates are equal, return True.

        Parameters:
            other: Another instance to compare with this position.
        """
        # an __eq__ method needs to support any object for example
        # so it can handle `Position(1, 2) == 2`
        # https://www.pythontutorial.net/python-oop/python-__eq__/
        if not isinstance(other, Position):
            return False
        return self.get_x() == other.get_x() and self.get_y() == other.get_y()

    def __hash__(self) -> int:
        """
        Calculate and return a hash code value for this position instance.

        This allows Position instances to be used as keys in dictionaries.

        A hash should be based on the unique data of a class, in the case
        of the position class, the unique data is the x and y values.
        Therefore, we can calculate an appropriate hash by hashing a tuple of
        the x and y values.
        
        Reference: https://stackoverflow.com/questions/17585730/what-does-hash-do-in-python
        """
        return hash((self.get_x(), self.get_y()))

    def __repr__(self) -> str:
        """
        Return the representation of a position instance.

        The format should be 'Position({x}, {y})' where {x} and {y} are replaced
        with the x and y value for the position.

        Examples:
            >>> repr(Position(12, 21))
            'Position(12, 21)'
            >>> Position(12, 21).__repr__()
            'Position(12, 21)'
        """
        return f"Position({self.get_x()}, {self.get_y()})"

    def __str__(self) -> str:
        """
        Return a string of this position instance.

        The format should be 'Position({x}, {y})' where {x} and {y} are replaced
        with the x and y value for the position.
        """
        return self.__repr__()

class Entity:
    """
    Entity is an abstract class that is used to represent anything that can appear on the game’s grid.

    Consider "player" and "zoombies" as type of entity.
    """

    def step(self, position: Position, game: "Game") -> None:
        """
        The step method is called on every entity in the game grid after each move made by the player, it controls
        what actions an entity will perform during the step event.

        Parameters:
            position(Position): The position of this entity when the step event is triggered.
            game(Game): The current game being played.
        """
    
    def display(self) -> str:
        """
        Return the character used to represent this entity in a text-based grid
        """
        raise NotImplementedError
    
    def __repr__(self) -> str:
        """
        Return a string representation of this entity
        """
        return "%s()" % (self.__class__.__name__)

class Player(Entity):   
    """
    Player class inherits from Entity class

    A player is a subclass of the entity class that represents the player that the user controls on the game grid.
    """
    def display(self) -> str:
        """
        Return the character used to represent the player entity in a text-based grid. Return "P" for player
        """
        return "P"

class Hospital(Entity):
    """
    A hospital is a subclass of the entity class that represents the hospital in the grid.
    
    The hospital is the entity that the player has to reach in order to win the game.
    """
    def display(self) -> str:
        """
        Return the character used to represent the hospital entity in a text-based grid. Return "H" for hospital 
        """
        return "H"

For the grid class the code is:

class Grid():
    """
    The Grid class is used to represent the 2D grid of entities.
    
    The grid can vary in size but it is always a square.
    
    Each (x, y) position in the grid can only contain one entity at a time.
    """
    def __init__(self, size):
        
        #A grid is constructed with a size that dictates the length and width of the grid.
        
        self._size = size
        self._reentity = {}
        self._serializedict = {}
    
    def get_size(self) -> int:
        # Returns the size of the grid.
        return self._size

    def in_bounds(self, position: Position) -> bool:
        """   
        Return True if the given position is within the bounds of the grid.

        Parameter: 
            position(Position): An (x, y) position that we want to check is within the bounds of the grid.
        """
        if ((position._x >= 0) & (position._x < self._size)) & ((position._y >= 0) & (position._y < self._size)):
            return True
        else:
            return False

    def add_entity(self, position: Position, entity: Entity) -> None:
        """
        Place a given entity at a given position of the grid.
        
        Parameter:
            position(Position): An (x, y) position in the grid to place the entity.
            entity(Entity): The entity to place on the grid.
        """
        if ((position._x < 0) | (position._x >= self._size)) | ((position._y < 0) | (position._y >= self._size)):
            self._reentity[position] = entity
            self._reentity.popitem()
        else:
            self._reentity[position] = entity
    
        
        
    def get_entity(self, position: Position) -> Optional[Entity]:
        """
        Return the entity that is at the given position in the grid.
        
        Parameter:
            position(Position): The (x, y) position in the grid to check for an entity
        """
        if ((position._x < 0) | (position._x >= self._size)) | ((position._y < 0) | (position._y >= self._size)):
            return None
        else:
            return self._reentity.get(position)

    def remove_entity(self, position: Position) -> None:
        """
        Remove the entity, if any, at the given position.

        Parameter:
            position(Position): An (x, y) position in the grid from which the entity is removed.
        """
        self._reentity.clear()

    def get_mapping(self) -> Dict[Position, Entity]:
        """
        Return a dictionary with position instances as the keys and entity instances as the values.
        """
        for position, entity in self._reentity.items():
            return self._reentity

    def get_entities(self) -> List[Entity]:
        """
        Return a list of all the entities in the grid.
        """
        temp = []
        entity_list = []
        for position, entity in self._reentity.items():
            temp = entity
            entity_list.append(temp)
        return entity_list
    
    def move_entity(self, start: Position, end: Position) -> None:
        """
        Move an entity from the given start position to the given end position.
            • If the end position or start position is out of the grid bounds, do not attempt to move.
            • If there is no entity at the given start position, do not attempt to move.
            • If there is an entity at the given end position, replace that entity with the entity from the start position.
        The start position should not have an entity after moving.

        Parameter: 
            start(Position): The position the entity is in initially.
            end(Position): The position to which the entity will be moved.
        """
        
        if ((end._x < 0) | (end._x >= self._size)) | ((end._y < 0) | (end._y >= self._size)):
            self._reentity.update(self._reentity)
            self._reentity.popitem()
        elif ((start._x < 0) | (start._x >= self._size)) | ((start._y < 0) | (start._y >= self._size)):
            self._reentity.update(self._reentity)
            self._reentity.popitem()
        #elif (self._reentity(start) not in start):
        else:
            self._reentity.update(self._reentity)
            self._reentity.pop(start)
        """
        if start not in self._reentity:
            return
        for start, entity in self._reentity:
            self._reentity[end] = entity
            self._reentity.pop(start)
        #self._reentity.update(start)
        #self._reentity.update(self._reentity)
        """

    def find_player(self) -> Optional[Position]:
        """
        Return the position of the player within the grid.
        """
        for position in self._reentity:
            return position

    def serialize(self) -> Dict[Tuple[int, int], str]:
        """
        Serialize the grid into a dictionary that maps tuples to characters.
        
        The tuples should have two values, the x and y coordinate representing a postion. The characters are the display
        representation of the entity at that position. i.e. ‘P’ for player, ‘H’ for hospital.
        
        Only positions that have an entity should exist in the dictionary.
        """
        for entity in self._reentity:
            self._serializedict.update(self._reentity)
        if entity in self._serializedict is Player():
            self._serializedict = {(Position.get_x(entity), Position.get_y(entity)): Player.display(entity)}
        else:
            self._serializedict = {(Position.get_x(entity), Position.get_y(entity)): Hospital.display(entity)}
        return self._serializedict

For the method move_entity(self, start: Position, end: Position) -> None I should have the result enter image description here

However, I run my code and I cannot return the Player() to the end position.

For the method serialize(self) -> Dict[Tuple[int, int], str] I should have the result enter image description here

However, I run the code and I only got the {(3, 20): 'H'} return to my new dictionary.

Could anyone please help to solve this problem as I am stuck here for days. Thanks in advance!

HY2000
  • 171
  • 1
  • 10
  • Your serialize method will always return a dictionary composed of a single item since the if-then-else statement will create a new dictionary (=> the for loop is useless). What is `entity in self._serializedict is Player()` supposed to mean? – qouify Apr 13 '21 at 06:49
  • I have two entities which are player and hospital. So the code entity in self._serializedict is Player() is suppose to return the "P". If I don't use the for loop, how can I update the original dictionary to a new dictionary? – HY2000 Apr 13 '21 at 07:09
  • Try `self._serializedict[Position.get_x(entity), Position.get_y(entity)] = Player.display(entity)` instead. Also `_serializedict` should not be an attribute of `self` since it's only used in that method. – qouify Apr 13 '21 at 07:47

0 Answers0