Ejemplo n.º 1
0
class Droid:
    def __init__(self) -> None:
        with open_fixture("day15") as fp:
            data = decode(fp.readline())
        self.vm = IntcodeVM(data)
        self.grid = Grid()
        self.pos = Position(0, 0)
        self.oxygen_system_pos = Position(0, 0)

    @property
    def cell(self) -> Cell:
        return self.grid[self.pos]

    def move(self, direction: Direction) -> bool:
        self.vm.io_push(direction.value)
        while not self.vm.stdout:
            self.vm.step()
        status = Status(self.vm.io_pop())
        pos = self.pos.move(direction)
        self.grid.set_status(pos, status)
        if status.passable:
            self.pos = pos
            if status == Status.OXYGENATED:
                self.oxygen_system_pos = pos
            return True
        return False

    def explore(self) -> bool:
        # first explore unexplored cells
        for direction in Direction.all():
            npos = self.pos.move(direction)
            if npos not in self.grid:
                if self.move(direction):
                    return True

        # invariant: all neighbors are known

        # quit if home again
        if not self.pos:
            return False

        # move back towards home
        options = {}
        for direction in Direction.all():
            npos = self.pos.move(direction)
            cell = self.grid[npos]
            if cell.status == Status.OKAY:
                options[cell.distance] = direction
                continue
        assert options
        best = sorted(options.keys())[0]
        assert best < self.cell.distance
        direction = options[best]
        assert self.move(direction)
        return True
Ejemplo n.º 2
0
class Robot:
    def __init__(self, program: Data) -> None:
        self.vm = IntcodeVM(program)
        self.grid = Grid()
        self.orientation = Orientation.UP
        self.position = (0, 0)

    def step(self) -> bool:
        # get current color
        self.vm.io_push(self.grid[self.position].value)

        # run the program until output is availble
        while len(self.vm.stdout) < 2:
            if not self.vm.step():
                return False

        # paint
        color = Color(self.vm.io_pop())
        self.grid[self.position] = color

        # turn
        direction = self.vm.io_pop()
        if direction:
            self.orientation = self.orientation.turn_right()
        else:
            self.orientation = self.orientation.turn_left()

        # move
        if self.orientation == Orientation.UP:
            self.position = (self.position[0], self.position[1] - 1)
        if self.orientation == Orientation.RIGHT:
            self.position = (self.position[0] + 1, self.position[1])
        if self.orientation == Orientation.DOWN:
            self.position = (self.position[0], self.position[1] + 1)
        if self.orientation == Orientation.LEFT:
            self.position = (self.position[0] - 1, self.position[1])

        return not self.vm.halted

    def run(self) -> None:
        while self.step():
            pass
Ejemplo n.º 3
0
class Ascii:
    def __init__(
        self,
        wake_up: bool = False,
    ):
        with open_fixture("day17") as fp:
            data = decode(fp.readline())
        self.vm = IntcodeVM(data)
        if wake_up:
            self.vm.data[0] = 2

    def putc(self, c: int) -> None:
        """
        Block until the character is written to the vm input buffer.
        """
        assert not self.vm.stdin
        assert not self.vm.stdout
        self.vm.io_push(c)
        while self.vm.step() and self.vm.stdin:
            assert not self.vm.stdout

    def write(self, s: str) -> None:
        """
        Block until the whole string is written to the vm input buffer.
        """
        for c in s:
            self.putc(ord(c))

    def getc(self) -> str:
        """
        Block until a character is read from the vm output buffer.
        """
        assert not self.vm.stdin
        assert not self.vm.stdout
        while self.vm.step():
            if self.vm.stdout:
                return chr(self.vm.io_pop())
        return ""

    def readline(self) -> str:
        """
        Block until a line is read from the vm output buffer.
        """
        with StringIO() as s:
            while True:
                c = self.getc()
                if not c:
                    break
                s.write(c)
                if c == "\n":
                    break
            return s.getvalue()

    def readgrid(self) -> str:
        """
        Block until a whole grid is read from the vm output buffer.
        """
        with StringIO() as s:
            for _ in range((GRID_WIDTH + 1) * GRID_HEIGHT):
                c = self.getc()
                s.write(c)
                if not c:
                    break
            assert not self.vm.stdout
            return s.getvalue()

    def get_dust_count(self) -> int:
        """
        Run the program to completion and return the sum of dust collected.
        """
        while self.vm.step():
            continue
        return self.vm.stdout[len(self.vm.stdout) - 1]