def move_ghost(self, direction, ghost_index):
        """Moves the given ghost in direction, where direction is leads the
        ghost to a valid location.
        """
        if ghost_index >= len(self.ghost_coords):
            # This ghost does not exist
            return

        new_coord = coord_class.Coordinate(self.ghost_coords[ghost_index].x,
                                           self.ghost_coords[ghost_index].y)

        # Adjust new_coord depending on pacman's desired direction
        if direction == d.Direction.UP:
            new_coord.y += 1

        elif direction == d.Direction.DOWN:
            new_coord.y -= 1

        elif direction == d.Direction.LEFT:
            new_coord.x -= 1

        elif direction == d.Direction.RIGHT:
            new_coord.x += 1

        self.prev_ghost_coords[ghost_index] = coord_class.Coordinate(
            self.ghost_coords[ghost_index].x, self.ghost_coords[ghost_index].y)
        self.ghost_coords[ghost_index] = coord_class.Coordinate(
            new_coord.x, new_coord.y)
Beispiel #2
0
    def move_pacman(self, directions):
        """Moves all pacman in self.pacman_coords in directions[i] (indexed the same 
        as self.pacman_coords), where each direction is leads pacman to a valid location.
        """
        for index, direction in enumerate(directions):
            if direction == d.Direction.NONE:
                # No action needed
                return

            new_coord = coord_class.Coordinate(self.pacman_coords[index].x, self.pacman_coords[index].y)
            
            # Adjust new_coord depending on pacman's desired direction
            if direction == d.Direction.UP:
                new_coord.y += 1

            elif direction == d.Direction.DOWN:
                new_coord.y -= 1

            elif direction == d.Direction.LEFT:
                new_coord.x -= 1

            elif direction == d.Direction.RIGHT:
                new_coord.x += 1
            
            self.prev_pacman_coords[index] = coord_class.Coordinate(self.pacman_coords[index].x, self.pacman_coords[index].y)
            self.pacman_coords[index] = coord_class.Coordinate(new_coord.x, new_coord.y)
    def move_pacman(self, direction, pacman_index):
        """Moves the pacman in self.pacman_coords at pacman_index in direction, where the direction 
        leads pacman to a valid location.

        If a pacman is marked as dead, it will not be moved.
        """
        if self.pacman_coords[pacman_index] in self.dead_pacmen:
            # This pacman is dead, don't move it
            return

        if direction == d.Direction.NONE:
            # No action needed
            return

        new_coord = coord_class.Coordinate(self.pacman_coords[pacman_index].x,
                                           self.pacman_coords[pacman_index].y)

        # Adjust new_coord depending on pacman's desired direction
        if direction == d.Direction.UP:
            new_coord.y += 1

        elif direction == d.Direction.DOWN:
            new_coord.y -= 1

        elif direction == d.Direction.LEFT:
            new_coord.x -= 1

        elif direction == d.Direction.RIGHT:
            new_coord.x += 1

        self.prev_pacman_coords[pacman_index] = coord_class.Coordinate(
            self.pacman_coords[pacman_index].x,
            self.pacman_coords[pacman_index].y)
        self.pacman_coords[pacman_index] = coord_class.Coordinate(
            new_coord.x, new_coord.y)
Beispiel #4
0
    def move(self):
        """Moves the WallCarver, generating new travel parameters if the travel
        distance is reached.
        """
        if self.travel_distance <= 0:
            self.get_travel_distance()
            self.get_direction()

        new_coord = coord_class.Coordinate(self.coord.x, self.coord.y)

        if self.direction == d.Direction.UP:
            new_coord.y += 1

        elif self.direction == d.Direction.DOWN:
            new_coord.y -= 1

        elif self.direction == d.Direction.LEFT:
            new_coord.x -= 1

        elif self.direction == d.Direction.RIGHT:
            new_coord.x += 1

        if new_coord.x >= 0 and new_coord.y >= 0 and new_coord.x < self.max_x and new_coord.y < self.max_y:
            self.coord = coord_class.Coordinate(new_coord.x, new_coord.y)

        self.travel_distance -= 1
Beispiel #5
0
    def __init__(self, config, initial_instance=False):
        """Initializes the GPacWorld class.
        
        Where config is a Config object for the GPac problem and initial_instance
        determines if a random world should be generated yet.
        """
        self.config = config

        # Load configuration file settings
        self.width = int(self.config.settings['width'])
        self.height = int(self.config.settings['height'])
        self.pill_density = float(self.config.settings['pill density']) / 100
        self.wall_density = float(self.config.settings['wall density']) / 100
        self.num_pacmen = int(self.config.settings['num pacmen'])
        self.num_ghosts = int(self.config.settings['num ghosts'])
        self.fruit_spawn_prob = float(self.config.settings['fruit spawn probability'])
        self.fruit_score = int(self.config.settings['fruit score'])
        self.time_multiplier = int(self.config.settings['time multiplier'])

        # Create initial world attributes
        self.pacman_coords= [coord_class.Coordinate(0, self.height - 1) for _ in range(self.num_pacmen)]
        self.ghost_coords = [coord_class.Coordinate(self.width - 1, 0) for _ in range(self.num_ghosts)]
        self.wall_coords = set([])
        self.pill_coords = set([])
        self.fruit_coord = set([])
        self.time_remaining = self.time_multiplier * self.width * self.height
        self.total_time = self.time_remaining
        self.num_pills_consumed = 0
        self.num_fruit_consumed = 0
        self.score = 0

        self.prev_pacman_coords = []
        for pacman_coord in self.pacman_coords:
            self.prev_pacman_coords.append(coord_class.Coordinate(pacman_coord.x, pacman_coord.y))

        self.prev_ghost_coords = []
        for ghost_coord in self.ghost_coords:
            self.prev_ghost_coords.append(coord_class.Coordinate(ghost_coord.x, ghost_coord.y))
        
        # Create helper set of all coordinates
        self.all_coords = set([])

        for x in range(self.width):
            for y in range(self.height):
                self.all_coords.add(coord_class.Coordinate(x, y))

        # Place walls and pills in the world
        # Only do this if the world is not being created for the first time
        # Subsequent runs of the GP will ensure random board generation
        if not initial_instance:
            self.generate_world()

        # Create & write to world file
        self.world_file = world_file_class.WorldFile(self.config)
        self.world_file.save_first_snapshot(self.width, self.height, self.pacman_coords,
            self.wall_coords, self.ghost_coords, self.pill_coords, self.time_remaining)
Beispiel #6
0
    def get_move(self, ghost_id, game_state):
        """Produces a move based on game_state.

        Note: for assignment 2b, the move is randomized.
        """
        while True:
            # Choose a random direction
            direction_to_try = random.choice(self.POSSIBLE_MOVES)

            # Determine if this direction is valid
            new_coord = coord_class.Coordinate(game_state.ghost_coords[ghost_id].x, game_state.ghost_coords[ghost_id].y)
            if direction_to_try == d.Direction.UP:
                new_coord.y += 1

            elif direction_to_try == d.Direction.DOWN:
                new_coord.y -= 1

            elif direction_to_try == d.Direction.LEFT:
                new_coord.x -= 1

            elif direction_to_try == d.Direction.RIGHT:
                new_coord.x += 1
            
            if self.check_valid_location(new_coord, game_state):
                break # We have found a valid direction

        return direction_to_try
    def randomly_spawn_fruit(self):
        """Probabilistically spawns a fruit in the world.

        Note that if a fruit already exists, another cannot be spawned.

        A fruit can only spawn in cell that is not occupied by pacman, not
        occupied by a wall, and not occupied by a pill.
        """
        if len(self.fruit_coord):
            # A fruit already exists
            return

        if random.random() <= self.fruit_spawn_prob:
            possible_coords = []
            for coord in list(
                    self.all_coords.difference(set(
                        self.pacman_coords)).difference(
                            self.wall_coords).difference(self.pill_coords)):
                possible_coords.append(coord_class.Coordinate(
                    coord.x, coord.y))

            random.shuffle(possible_coords)

            for possible_fruit_coord in possible_coords:
                self.fruit_coord.add(possible_fruit_coord)
                break
        def get_nearest_distance(ghost_coord, object):
            """Returns the distance between the given ghost coordinate
            and the nearest instance of type object.
            """
            def get_distance(coord1, coord2):
                """Returns the Manhattan distance between the given coordinates."""
                if not coord1 or not coord2:
                    return -1

                return abs(coord1.x - coord2.x) + abs(coord1.y - coord2.y)

            if object == 'ghost':
                coords_to_search = game_state.ghost_coords
                coords_to_search = [
                    coord_class.Coordinate(c.x, c.y)
                    for c in game_state.ghost_coords
                    if not c.x == ghost_coord.x and not c.y == ghost_coord.y
                ]

            elif object == 'pacman':
                coords_to_search = game_state.pacman_coords

            else:
                coords_to_search = []

            min_distance = ARBITRARY_LARGE_NUMBER
            for coord in coords_to_search:
                min_distance = min(min_distance,
                                   get_distance(ghost_coord, coord))

            return min_distance
Beispiel #9
0
    def __init__(self, config):
        """Initializes the WorldFile class.

        Where config is a Config object.
        """
        self.config = config
        self.file_str = ''
        self.prev_seen_fruit = coord_class.Coordinate(-1, -1)
    def get_adj_coords(self, coord):
        """Returns a list of coordinates adjacent to coord.

        Where the returned coordinate list includes only valid coordinates.
        """
        adj_coords = []

        if not coord.x == 0:
            adj_coords.append(coord_class.Coordinate(coord.x - 1, coord.y))

        if not coord.x == self.width - 1:
            adj_coords.append(coord_class.Coordinate(coord.x + 1, coord.y))

        if not coord.y == 0:
            adj_coords.append(coord_class.Coordinate(coord.x, coord.y - 1))

        if not coord.y == self.height - 1:
            adj_coords.append(coord_class.Coordinate(coord.x, coord.y + 1))

        return adj_coords
Beispiel #11
0
    def get_move(self, game_state):
        """Checks all possible moves against the state evaluator and 
        determines which move is optimal, returning that move.

        This is performed for each pacman presented as part of the game state.
        """

        def move_pacman(pacman_coord, direction):
            """Alters pacman's new coordinate to indicate movement in direction.
            
            Returns True if the new position is valid, False otherwise.
            """
            if direction == d.Direction.NONE:
                # No action needed
                return True

            # Adjust new_coord depending on pacman's desired direction
            if direction == d.Direction.UP:
                pacman_coord.y += 1

            elif direction == d.Direction.DOWN:
                pacman_coord.y -= 1

            elif direction == d.Direction.LEFT:
                pacman_coord.x -= 1

            elif direction == d.Direction.RIGHT:
                pacman_coord.x += 1
            
            if self.check_valid_location(pacman_coord, game_state):
                return True

            return False


        best_eval_directions = []

        for pacman_coord in game_state.pacman_coords:
            best_eval_result = -1 * ARBITRARY_LARGE_NUMBER
            best_eval_direction = d.Direction.NONE

            for direction in POSSIBLE_MOVES:
                tmp_pacman_coord = coord_class.Coordinate(pacman_coord.x, pacman_coord.y)

                if move_pacman(tmp_pacman_coord, direction):
                    eval_result = self.evaluate_state(game_state, tmp_pacman_coord)[0]

                    if eval_result > best_eval_result:
                        best_eval_result = eval_result
                        best_eval_direction = direction
            
            best_eval_directions.append(best_eval_direction)

        return best_eval_directions
    def reset(self):
        """Resets all world elements except for wall placements."""
        # Regenerate unit coordinates
        self.pacman_coords = [
            coord_class.Coordinate(0, self.height - 1)
            for _ in range(self.num_pacmen)
        ]
        self.ghost_coords = [
            coord_class.Coordinate(self.width - 1, 0)
            for _ in range(self.num_ghosts)
        ]

        self.prev_pacman_coords = []
        for pacman_coord in self.pacman_coords:
            self.prev_pacman_coords.append(
                coord_class.Coordinate(pacman_coord.x, pacman_coord.y))

        self.dead_pacmen = set([])

        self.prev_ghost_coords = []
        for ghost_coord in self.ghost_coords:
            self.prev_ghost_coords.append(
                coord_class.Coordinate(ghost_coord.x, ghost_coord.y))

        self.fruit_coord = set([])
        self.pill_coords = set([])

        # Add pills to the world
        for c in self.orig_pill_coords:
            self.pill_coords.add(c)

        self.time_remaining = self.time_multiplier * self.width * self.height
        self.world_file.flush()
        self.num_pills_consumed = 0
        self.num_fruit_consumed = 0
        self.score = 0
    def get_move(self, game_state, ghost_index):
        """Checks all possible moves against the state evaluator and 
        determines which move is optimal, returning that move for the ghost at ghost_index
        in game_state.
        """
        def move_ghost(ghost_coord, direction):
            """Alters ghost's new coordinate to indicate movement in direction.
            
            Returns True if the new position is valid, False otherwise.
            """
            if direction == d.Direction.NONE:
                # No action needed
                return True

            # Adjust new_coord depending on ghost's desired direction
            if direction == d.Direction.UP:
                ghost_coord.y += 1

            elif direction == d.Direction.DOWN:
                ghost_coord.y -= 1

            elif direction == d.Direction.LEFT:
                ghost_coord.x -= 1

            elif direction == d.Direction.RIGHT:
                ghost_coord.x += 1

            if self.check_valid_location(ghost_coord, game_state):
                return True

            return False

        best_eval_result = -1 * ARBITRARY_LARGE_NUMBER
        best_eval_direction = d.Direction.NONE

        for direction in POSSIBLE_MOVES:
            tmp_ghost_coord = coord_class.Coordinate(
                game_state.ghost_coords[ghost_index].x,
                game_state.ghost_coords[ghost_index].y)

            if move_ghost(tmp_ghost_coord, direction):
                eval_result = self.evaluate_state(game_state, tmp_ghost_coord)

                if eval_result > best_eval_result:
                    best_eval_result = eval_result
                    best_eval_direction = direction

        return best_eval_direction
Beispiel #14
0
    def __init__(self, x, y, config):
        """Initializes the WallCarver class."""
        self.config = config
        self.max_travel_dist = int(self.config.settings['max wall carver travel distance'])
        self.min_travel_dist = int(self.config.settings['min wall carver travel distance'])
        self.max_x = int(self.config.settings['width'])
        self.max_y = int(self.config.settings['height'])

        self.POSSIBLE_MOVES = [d.Direction.UP, d.Direction.DOWN, d.Direction.LEFT, d.Direction.RIGHT]

        self.coord = coord_class.Coordinate(x, y)

        self.get_travel_distance()
        self.get_direction()

        self.seen_coords = set([])

        self.marked_for_death = False
        def add_walls():
            """Places (carves out) walls in the world such that every non-wall cell is 
            accessible from every other non-wall cell.
            """
            def assign_unit_starting_coords(wall_carver_list):
                """Assigns the first two WallCarvers in wall_carver_list to have 
                the unit (pacman & ghosts) starting coords, ensuring these
                coords are carved out.
                """
                wall_carver_list[0].coord = self.pacman_coords[0]
                wall_carver_list[1].coord = self.ghost_coords[0]

            # Create WallCarver population
            # Note: num wall carvers should be greater than or equal to two
            wall_carvers = [
                wall_carver_class.WallCarver(random.randint(0, self.width),
                                             random.randint(0, self.height),
                                             self.config)
                for _ in range(int(self.config.settings['num wall carvers']))
            ]
            assign_unit_starting_coords(wall_carvers)

            # Get walls to carve
            walls_to_carve = []
            for coord in self.all_coords:
                walls_to_carve.append(coord_class.Coordinate(coord.x, coord.y))

            past_seen_carved_coords = set([])

            # Calculate wall density
            num_coords = len(walls_to_carve)
            num_walls = num_coords
            wall_density = num_walls / num_coords
            completed_circuit = False

            while wall_density > self.wall_density or not completed_circuit:
                if not len(wall_carvers):
                    # Re-spawn WallCarvers
                    wall_carvers = []

                    for i in range(
                            int(self.config.
                                settings['num respawn wall carvers'])):
                        spawn_coord = random.choice(list(walls_to_carve))
                        wall_carvers.append(
                            wall_carver_class.WallCarver(
                                spawn_coord.x, spawn_coord.y, self.config))

                    completed_circuit = False

                for wall_carver in wall_carvers:
                    if wall_carver.coord_already_carved(
                            wall_carvers
                    ) or wall_carver.coord in past_seen_carved_coords:
                        # This coord has already been seen by another WallCarver
                        wall_carver.mark_for_death()

                    elif wall_carver.coord in walls_to_carve:
                        # This is a new coord. Remove the wall
                        walls_to_carve.remove(wall_carver.coord)
                        wall_carver.seen_coords.add(wall_carver.coord)
                        num_walls -= 1

                    wall_carver.move()

                # Update past seen carved coordinates with coordinate sets of agents marked for death
                for marked_wall_carver in [
                        wall_carver for wall_carver in wall_carvers
                        if wall_carver.marked_for_death
                ]:
                    past_seen_carved_coords = past_seen_carved_coords.union(
                        marked_wall_carver.seen_coords)

                # Kill WallCarvers marked for death
                wall_carvers = [
                    wall_carver for wall_carver in wall_carvers
                    if not wall_carver.marked_for_death
                ]

                if not len(wall_carvers):
                    completed_circuit = True

                wall_density = num_walls / num_coords

            self.wall_coords = walls_to_carve