예제 #1
0
def visible_neighbors(seats: SeatMap,
                      origin: Point) -> typing.List[SeatStatus]:
    directions = Point.directions8
    statuses = []

    for x, y in directions:
        for magnitude in itertools.count(1):
            dx, dy = x * magnitude, y * magnitude
            p = origin.displace(dx, dy)

            if p not in seats:
                break

            if seats[p] != SeatStatus.Floor:
                statuses.append(seats[p])
                break

    return statuses
예제 #2
0
class Explorer:
    def __init__(self, tape):
        self.tape = tape
        self.position = Point(0, 0)
        self.graph = collections.defaultdict(set)
        self.oxygen = None

    def explore(self):
        places_to_visit = collections.deque([self.position])
        visited = {self.position}

        while places_to_visit:
            next_point = places_to_visit.pop()
            self.move_to(next_point)

            unvisited_neighbors = set(self.position.neighbors()) - visited
            for neighbor in unvisited_neighbors:
                status = self.explore_adjacent_point(neighbor)

                if status == StatusCode.Wall:
                    visited.add(neighbor)

                if status in [StatusCode.Step, StatusCode.Oxygen]:
                    self.graph[self.position].add(neighbor)
                    self.graph[neighbor].add(self.position)
                    places_to_visit.append(neighbor)

                if status == StatusCode.Oxygen:
                    self.oxygen = neighbor

            visited.add(self.position)

    def find_path(self, start, end):
        import heapq as h

        distances = {start: 0}
        heap = [(0, start)]
        prev_node = dict()

        while end not in prev_node:
            weight, node = h.heappop(heap)

            unvisited_neighbors = self.graph[node] - distances.keys()

            for neighbor in unvisited_neighbors:
                prev_node[neighbor] = node

                distance = weight + 1
                distances[neighbor] = weight
                h.heappush(heap, (distance, neighbor))

        cur_node = end
        path = [end]

        while cur_node != start:
            previous_node = prev_node[cur_node]
            path.append(previous_node)
            cur_node = previous_node

        return list(reversed(path))[1:]

    def distances_from(self, start):
        import heapq as h

        distances = {start: 0}
        heap = [(0, start)]

        while heap:
            weight, node = h.heappop(heap)

            unvisited_neighbors = self.graph[node] - distances.keys()

            for neighbor in unvisited_neighbors:
                distance = weight + 1
                distances[neighbor] = weight
                h.heappush(heap, (distance, neighbor))

        return distances

    def move_direction(self, direction):
        input_code = direction_to_int(direction)
        status_code = self.tape.run_until_output(provide_input=input_code)[0]
        status = StatusCode(status_code)

        if status != StatusCode.Wall:
            self.position = self.position.displace(*direction.value)

        return status

    def move_to(self, destination):
        if self.position == destination:
            return

        for point in self.find_path(self.position, destination):
            self.move_direction(self.position.direction_to(point))

    def explore_adjacent_point(self, point):
        direction = self.position.direction_to(point)
        status = self.move_direction(direction)

        if status != StatusCode.Wall:
            self.move_direction(direction.inverse_direction())

        return status