Beispiel #1
0
    def __init__(self, inp=None, mode=None):
        # key (tuple) : coordinates
        self.map = collections.defaultdict(
            tuple  # value: current_color (int), painted (bool)
        )

        self.computer = IntcodeComputer(inp, mode)

        self.direction = 0  # up
Beispiel #2
0
    def count_ones(self, max_x, max_y):
        _map = collections.defaultdict(int)
        for y in range(max_y):
            for x in range(max_x):
                computer = IntcodeComputer()
                computer.feed(x)
                computer.feed(y)
                # print(f'feed ({x}, {y})')
                res = next(computer)
                # print(f'received {res}')
                _map[(x, y)] = res

        return sum(val for val in _map.values() if val)
Beispiel #3
0
class SpacePolice:
    def __init__(self, inp=None, mode=None):
        # key (tuple) : coordinates
        self.map = collections.defaultdict(
            tuple  # value: current_color (int), painted (bool)
        )

        self.computer = IntcodeComputer(inp, mode)

        self.direction = 0  # up

    def _update_direction(self, turn):
        if turn not in (LEFT, RIGHT):
            raise ValueError()
        self.direction = (self.direction + (-1)**(turn + 1)) % 4
        return self.direction

    def _get_step(self):
        if self.direction == 0:
            return (0, -1)
        if self.direction == 1:
            return (-1, 0)
        if self.direction == 2:
            return (0, 1)
        if self.direction == 3:
            return (1, 0)

    def paint(self):
        """
        The Intcode program will serve as the brain of the robot

        Returns:
            int: number of panels it paints at least once, regardless of color

        """
        pos = (0, 0)
        poses = [pos]
        dirs = [self.direction]
        while True:
            # print(list(self.computer.memory.values()))
            try:
                # provide 0 if the robot is over a black panel or 1 if the robot is over a white panel.
                state = self.map.get(pos)
                # print(pos)

                curr_color = 1 if state and state[0] else 0
                if not state:
                    inp_msg = f'default ({curr_color})'
                else:
                    inp_msg = curr_color

                self.computer.feed(curr_color)
                print(f'input {inp_msg}')
                print()

                # First, it will output a value indicating the color to paint the panel the robot is over:
                # 0 means to paint the panel black, and 1 means to paint the panel white
                color = next(self.computer)
                # print('WHITE' if color else 'BLACK')

                # Second, it will output a value indicating the direction the robot should turn:
                # 0 means it should turn left 90 degrees, and 1 means it should turn right 90 degrees.
                turn = next(self.computer)
                # print('RIGHT' if turn else 'LEFT')

                print(f'on position {pos} got paint {color} turn {turn}')

                self.map[pos] = color, True

                self._update_direction(turn)

                step = self._get_step()
                pos = tuple(map(operator.add, pos, step))
                print(f'move to  {pos}')

                poses += [pos]
                dirs += [self.direction]

            except StopIteration as e:
                return sum(val[1] for val in self.map.values())
Beispiel #4
0
    def _bfs(self, root, computer=None, mode=1):
        state = 1
        computer = computer or IntcodeComputer()
        seen = {root: (state, computer)}
        queue = collections.deque([(root, 0, computer)])
        visit_order = []
        levels = []

        while queue:
            vertex, level, parent_computer = queue.popleft()
            visit_order.append(vertex)
            levels.append(level)

            if vertex in seen:
                _node = seen[vertex]
                _state = _node[0]
                if mode == 1 and _state == 2:
                    if self.to_draw:
                        # print(visit_order)
                        # print(levels)
                        ys = [pos[1] for pos in seen.keys()]
                        xs = [pos[0] for pos in seen.keys()]
                        min_y, max_y = min(ys), max(ys)
                        min_x, max_x = min(xs), max(xs)
                        print(
                            f'after: node {node} state {state} pos {computer.pos} base {computer.relative_base}'
                        )
                        # print(f'after: vertex {vertex} pos {parent_computer.pos} base {parent_computer.relative_base}')
                        print('y from {} to {}'.format(min_y, max_y))
                        print('x from {} to {}'.format(min_x, max_x))
                        for _y in reversed(range(min_y, max_y + 1)):
                            line = []
                            for _x in range(min_x, max_x + 1):
                                if (_x, _y) == (0, 0):
                                    _draw = '*'
                                if (_x, _y) == node:
                                    _draw = 'Ж'
                                else:
                                    _node = seen.get((_x, _y), (-1, ))
                                    _state = _node[0]
                                    _draw = TILE2DRAW[_state]
                                line.append(_draw)
                            print(''.join(line))
                        # end draw region
                    return vertex, level, parent_computer

            # for node in graph.get(vertex, [0, 1, 2, 3]):
            # Only four movement commands are understood: north (1), south (2), west (3), and east (4)
            # if to_draw:
            #     print(f'before: vertex {vertex} pos {parent_computer.pos} base {parent_computer.relative_base}')
            for direction in range(1, 5):
                node = self._get_node(vertex, direction)
                if node in seen:
                    continue

                computer = parent_computer.copy()

                computer.feed(direction)
                try:
                    state = next(computer)
                    # 0: The repair droid hit a wall. Its position has not changed.
                    # 1: The repair droid has moved one step in the requested direction.
                    # 2: The repair droid has moved one step in the requested direction; its new position is the location of the oxygen system.
                except StopIteration as e:
                    break

                # print('compare {node} to {vertex}:')
                # for i, val in enumerate(computer.memory):
                #     if val != seen[vertex][-1].memory[i]:
                #         print(i, val)
                # print('compare signals:')
                # print(computer.signals)
                # print(seen[vertex][-1].signals)

                if state == 0:
                    # 0: The repair droid hit a wall. Its position has not changed.
                    pass
                else:
                    queue.append((node, level + 1, computer))

                seen[node] = (state, computer)

                # draw region
                # if to_draw:
                #     ys = [pos[1] for pos in seen.keys()]
                #     xs = [pos[0] for pos in seen.keys()]
                #     min_y, max_y = min(ys), max(ys)
                #     min_x, max_x = min(xs), max(xs)
                #     print(f'after: node {node} state {state} pos {computer.pos} base {computer.relative_base}')
                #     # print(f'after: vertex {vertex} pos {parent_computer.pos} base {parent_computer.relative_base}')
                #     print('y from {} to {}'.format(min_y, max_y))
                #     print('x from {} to {}'.format(min_x, max_x))
                #     for _y in reversed(range(min_y, max_y + 1)):
                #         line = []
                #         for _x in range(min_x, max_x + 1):
                #             if (_x, _y) == (0, 0):
                #                 _draw = '*'
                #             if (_x, _y) == node:
                #                 _draw = 'Ж'
                #             else:
                #                 _node = seen.get((_x, _y), (-1,))
                #                 _state = _node[0]
                #                 _draw = TILE2DRAW[_state]
                #             line.append(_draw)
                #         print(''.join(line))
                #     # end draw region

        if mode == 1:
            raise RuntimeError('couldnt find oxygen')
        elif mode == 2:
            return max(levels)
        raise RuntimeError(f'unknown mode {mode}')
Beispiel #5
0
    def find_closest_square_under_beam(self, expected_width, expected_high):
        for y in range(750, 1500):
            for x in range(1500, 2000):
                computer = IntcodeComputer()
                computer.feed(x)
                computer.feed(y)
                # print(f'feed ({x}, {y})')
                value = next(computer)
                if not value:
                    continue

                computer = IntcodeComputer()
                computer.feed(x + 99)
                computer.feed(y)
                value = next(computer)
                if not value:
                    continue

                computer = IntcodeComputer()
                computer.feed(x)
                computer.feed(y + 99)
                value = next(computer)
                if not value:
                    continue

                return _get_part2_result(x, y)

        raise RuntimeError()
Beispiel #6
0
def part1(*args, **kwargs):
    return IntcodeComputer(*args, signals=[1], **kwargs).compute()