Example #1
0
def test_position_mode_equals_8(monkeypatch, capsys):
    codes = [3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8]

    set_input(monkeypatch, '8')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1

    set_input(monkeypatch, '5')
    Computer(codes).run()
    assert int(get_output(capsys)) == 0
Example #2
0
def test_immediate_mode_equals_8(monkeypatch, capsys):
    codes = [3, 3, 1108, -1, 8, 3, 4, 3, 99]

    set_input(monkeypatch, '8')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1

    set_input(monkeypatch, '10')
    Computer(codes).run()
    assert int(get_output(capsys)) == 0
Example #3
0
def test_jump_position_mode(monkeypatch, capsys):
    codes = [3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9]

    set_input(monkeypatch, '0')
    Computer(codes).run()
    assert int(get_output(capsys)) == 0

    set_input(monkeypatch, '8')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1
Example #4
0
def test_jump_immediate_mode(monkeypatch, capsys):
    codes = [3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]

    set_input(monkeypatch, '0')
    Computer(codes).run()
    assert int(get_output(capsys)) == 0

    set_input(monkeypatch, '8')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1
Example #5
0
def test_immediate_mode_less_than_8(monkeypatch, capsys):
    codes = [3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8]

    set_input(monkeypatch, '5')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1

    set_input(monkeypatch, '8')
    Computer(codes).run()
    assert int(get_output(capsys)) == 0
Example #6
0
 def run_and_return_grid(self, *, initial_color=0):
     cpu = Computer(self.program, [])
     grid = defaultdict(lambda: 0)
     location = complex(0, 0)
     direction = "U"
     grid[location] = initial_color
     # Input to program: 0 if over black (.) , 1 if over white (#)
     # Outputs two values: color to paint 0/black/. 1/white/#, then 0 = turn left, 1 = turn right
     while True:
         current_square = grid[location]
         cpu.add_input(current_square)
         cpu.execute()
         if cpu.state == "halted":
             break
         paint_color = cpu.pop_output()
         turn_dir = cpu.pop_output()
         grid[location] = paint_color
         if turn_dir == 1:
             direction = turn_right(direction)
         elif turn_dir == 0:
             direction = turn_left(direction)
         else:
             raise "Told to turn an invalid direction"
         location += COMPLEX_OF_DIR[direction]
     return grid
Example #7
0
class RepairDroid:
    def __init__(self, program):
        self.program = program
        self.cpu = Computer(self.program, [])

    def input(self, command):
        self.cpu.add_input(command)
        self.cpu.execute()
        return self.cpu.pop_output()

    def get_state(self):
        return copy.copy(self.cpu.memory)

    def set_state(self, state):
        self.cpu.memory = copy.copy(state)
Example #8
0
    def pick_up_items(self):
        print("=== Picking up all items")
        # Reset computer
        self.cpu = Computer(self.program, [])
        message = self.execute_str()
        loc = self.parse_title(message)

        for item in self.loc_of_item:
            if self.is_blacklisted(item):
                continue
            destination = self.loc_of_item[item]
            self.move(loc, destination)
            loc = destination
            self.loc = loc
            self.send_msg(f"take {item}")
            message = self.execute_str()
Example #9
0
    def part2(self):
        prog = self.create_program()

        # Load prog into computer, execute
        cpu = Computer(self.program, [])
        cpu.memory[0] = 2
        for instruction in prog:
            cpu.add_input(instruction)
        cpu.execute()
        result = []
        while cpu.has_output():
            result.append(cpu.pop_output())
        return result[-1]
Example #10
0
    def explore(self):
        self.cpu = Computer(self.program, [])
        self.loc = None
        # visited[ 'Hull Breach'] = true
        # dir_from_to[ ('Hull Breach', 'Holodeck') ] = 'north'
        # Possibly Delete: dirs_for_loc['Hull Breach'] = ['north', 'west', 'south']
        # state_for_loc['Hull Breach'] = (memory state for int comp)
        # loc_of_item['tambourine'] = 'Holodeck'
        # G = (networkx graph)
        self.visited = {}
        self.dir_from_to = {}
        self.dirs_for_loc = {}
        self.state_for_loc = {}
        self.loc_of_item = {}
        self.G = nx.Graph()

        self.explore_dfs(None, None)
Example #11
0
def test_computer_end_to_end(monkeypatch, capsys):
    codes = [
        3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31,
        1106, 0, 36, 98, 0, 0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999,
        1105, 1, 46, 1101, 1000, 1, 20, 4, 20, 1105, 1, 46, 98, 99
    ]

    set_input(monkeypatch, '7')
    Computer(codes).run()
    assert int(get_output(capsys)) == 999

    set_input(monkeypatch, '8')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1000

    set_input(monkeypatch, '9')
    Computer(codes).run()
    assert int(get_output(capsys)) == 1001
Example #12
0
def amplify_loop(program_in, phase_sequence):
    cpus = []
    for i in range(5):
        cpus.append(Computer(program_in, [phase_sequence[i]]))

    i = 0
    next_input = 0
    while True:
        cpus[i].add_input(next_input)
        cpus[i].execute()
        if cpus[i].state == "halted" and i == 4:
            # print("halted")
            return cpus[i].outputs[0]
        next_input = cpus[i].pop_output()
        i = (i + 1) % 5
Example #13
0
from sys import stdin
from aoc.computer import Computer
from aoc.instruction import parse_input

Computer(parse_input(stdin)).run()
Example #14
0
class Day21:
    def __init__(self, program):
        self.program = program
        self.cpu = Computer(self.program, [])

    def reset(self):
        self.cpu = Computer(self.program, [])

    def execute(self):
        self.cpu.execute()
        result = []
        while self.cpu.has_output():
            result.append(self.cpu.pop_output())
        self.display(result)

    def execute_silent(self):
        self.cpu.execute()
        result = []
        while self.cpu.has_output():
            result.append(self.cpu.pop_output())
        return result

    def display(self, result):
        print("\n")
        for char in result:
            if char < 255:
                print(chr(char), end="")
            else:
                print(char)

    def send(self, string):
        prog = self.prog_to_ascii(string)
        for instruction in prog:
            self.cpu.add_input(instruction)

    def prog_to_ascii(self, string):
        return [ord(s) for s in string]

    def run_springscript_interactive(self, prog_string_array):
        """ Runs springscript and prints to console. """
        self.reset()
        self.execute()
        self.send("\n".join(prog_string_array) + "\n")
        self.execute()

    def run_springscript_headless(self, prog_string_array):
        """ Runs springscript and returns the last output. """
        self.reset()
        self.execute_silent()
        self.send("\n".join(prog_string_array) + "\n")
        output = self.execute_silent()
        return output[-1]

    def part1(self):
        # This program was derived manually (as intended, I suspect)
        # Jump if (NOT A1) OR (NOT C AND D)
        part1_prog = ["NOT C J", "AND D J", "NOT A T", "OR T J", "WALK"]
        # self.run_springscript_interactive(part1_prog)
        return self.run_springscript_headless(part1_prog)

    def part2(self):
        # This program was derived manually (as intended, I suspect)
        part2_prog = [
            # (J) Jump if (C3) is missing and (D4) is filled
            #  - But not if E(5) and H8 are missing
            #  1. Fill J with E5 present or H5 present
            "NOT E J",
            "NOT J J",
            "OR H J",
            #  2. Fill T with C3 missing and D4 filled
            "NOT C T",
            "AND D T",
            # 3. Move T to J somehow
            "AND T J",
            # Also jump if A(1) is missing
            "NOT A T",
            "OR T J",
            # Also jump if A(2) is missing and D4 is filled  (Probably need to add somethign here)
            "NOT B T",
            "AND D T",
            "OR T J",
            "RUN",
        ]
        # self.run_springscript_interactive(part2_prog)
        return self.run_springscript_headless(part2_prog)
Example #15
0
 def reset(self):
     self.cpu = Computer(self.program, [])
Example #16
0
 def __init__(self, program_in):
     self.program = program_in
     self.cpu = Computer(self.program, [])
     self.grid = defaultdict(lambda: 0)
Example #17
0
class Breakout:
    def __init__(self, program_in):
        self.program = program_in
        self.cpu = Computer(self.program, [])
        self.grid = defaultdict(lambda: 0)

    def input(self, val):
        self.cpu.add_input(val)

    def add_quarters(self):
        self.cpu.memory[0] = 2

    def run_and_return_grid(self):
        cpu = self.cpu
        self.cpu.memory[0] = 2
        grid = self.grid

        cpu.execute()
        while cpu.has_output():
            x = cpu.pop_output()
            y = cpu.pop_output()
            what = cpu.pop_output()
            grid[complex(x, y)] = what

        return grid

    def is_halted(self):
        return self.cpu.is_halted()

    def display(self):
        system("clear")
        for y in range(25):
            for x in range(45):
                char = self.grid[complex(x, y)]
                print_char = " "
                if char == 1:
                    print_char = "W"
                elif char == 2:
                    print_char = "B"
                elif char == 3:
                    print_char = "="
                elif char == 4:
                    print_char = "*"
                print(print_char, end="")
            print("")
        print(f"Score {self.grid[complex(-1, 0)]}")

    def score(self):
        return self.grid[complex(-1, 0)]

    def get_move(self):
        grid = self.grid
        ball = list(grid.keys())[list(grid.values()).index(4)]
        ball_x = int(ball.real)
        paddle = list(grid.keys())[list(grid.values()).index(3)]
        paddle_x = int(paddle.real)
        if ball_x > paddle_x:
            return "r"
        if ball_x < paddle_x:
            return "l"
        return "."

    @staticmethod
    def part1(program_in):
        robot = Breakout(program_in)
        grid = robot.run_and_return_grid()
        return list(grid.values()).count(2)

    @staticmethod
    def part2(program_in, *, display_to_screen=False):
        robot = Breakout(program_in)
        grid = robot.run_and_return_grid()
        robot.add_quarters()
        if display_to_screen:
            robot.display()
        while True:
            a = robot.get_move()
            if a == "l":
                robot.input(-1)
            elif a == "r":
                robot.input(1)
            else:
                robot.input(0)
            if robot.is_halted():
                break
            grid = robot.run_and_return_grid()
            if display_to_screen:
                robot.display()
        return robot.score()
Example #18
0
def test_set_noun_and_verb():
    computer = Computer([1, 9, 10], 12, 2)
    assert computer.memory == [1, 12, 2]
Example #19
0
def calculate(codes: List[int], noun: int, verb: int) -> int:
    return Computer(codes, noun=noun, verb=verb).run()
Example #20
0
 def __init__(self, program):
     self.program = program
     self.cpu = Computer(self.program, [])
     self.grid = defaultdict(lambda: "?")
     self.filled_squares = {}
Example #21
0
class Day25:
    def __init__(self, program):
        self.program = program
        self.cpu = Computer(self.program, [])

    def get_state(self):
        return copy.copy(self.cpu.memory)

    def set_state(self, state):
        self.cpu.memory = copy.copy(state)

    def execute_silent(self):
        """ Execute CPU and return results as array. """
        self.cpu.execute()
        result = []
        while self.cpu.has_output():
            result.append(self.cpu.pop_output())
        return result

    def execute_str(self):
        """ Execute CPU and return results as str. """
        result = self.execute_silent()
        return self.num_to_str(result)

    def send_msg(self, string):
        print(f"> {string}")
        nums = self.string_to_nums(string + "\n")
        for i in nums:
            self.cpu.add_input(i)

    def opposite_dir(self, direction):
        opposites = {"west": "east", "east": "west", "south": "north", "north": "south"}
        if direction in opposites:
            return opposites[direction]
        raise ValueError(f"Don't know opposite of [{direction}]")

    def explore(self):
        self.cpu = Computer(self.program, [])
        self.loc = None
        # visited[ 'Hull Breach'] = true
        # dir_from_to[ ('Hull Breach', 'Holodeck') ] = 'north'
        # Possibly Delete: dirs_for_loc['Hull Breach'] = ['north', 'west', 'south']
        # state_for_loc['Hull Breach'] = (memory state for int comp)
        # loc_of_item['tambourine'] = 'Holodeck'
        # G = (networkx graph)
        self.visited = {}
        self.dir_from_to = {}
        self.dirs_for_loc = {}
        self.state_for_loc = {}
        self.loc_of_item = {}
        self.G = nx.Graph()

        self.explore_dfs(None, None)

    def explore_dfs(self, command_used, came_from):
        # Execute, read text and get room name
        message = self.execute_str()
        room_name = self.parse_title(message)
        loc = room_name
        self.loc = loc
        print(f"=== ExploreDFS [{loc}] ===")

        # Save the way we got here
        if command_used is not None and came_from is not None:
            self.G.add_edge(came_from, loc)
            self.dir_from_to[(came_from, loc)] = command_used
            self.dir_from_to[(loc, came_from)] = self.opposite_dir(command_used)

        # Been here before?
        if loc in self.visited:
            return

        # Mark as visited and save state
        self.visited[loc] = True
        self.state_for_loc[loc] = self.get_state()

        # Record items here
        for item in self.parse_items(message):
            self.loc_of_item[item] = loc

        directions = self.parse_directions(message)
        self.dirs_for_loc[loc] = directions

        for command in directions:
            # Load state
            self.set_state(self.state_for_loc[loc])

            # Move and recurse
            self.send_msg(command)
            self.explore_dfs(command_used=command, came_from=loc)

    def pick_up_items(self):
        print("=== Picking up all items")
        # Reset computer
        self.cpu = Computer(self.program, [])
        message = self.execute_str()
        loc = self.parse_title(message)

        for item in self.loc_of_item:
            if self.is_blacklisted(item):
                continue
            destination = self.loc_of_item[item]
            self.move(loc, destination)
            loc = destination
            self.loc = loc
            self.send_msg(f"take {item}")
            message = self.execute_str()

    def move(self, loc, destination):
        path = nx.shortest_path(self.G, loc, destination)
        path.pop(0)  # First item in path is always where we are
        while len(path) > 0:
            next_loc = path.pop(0)
            direction = self.dir_from_to[(loc, next_loc)]
            self.send_msg(direction)
            message = self.execute_str()
            room_name = self.parse_title(message)
            assert room_name == next_loc
            loc = next_loc
            self.loc = loc

    def try_all_items(self):
        print("=== Going to Security Checkpoint")
        destination = "Security Checkpoint"
        self.move(self.loc, destination)
        items = self.get_items()

        for item in items:
            self.send_msg(f"drop {item}")

        for n in range(len(items)):
            for these_items in list(combinations(items, n)):
                for item in these_items:
                    self.send_msg(f"take {item}")
                self.send_msg("south")

                message = self.execute_str()
                if self.cpu.is_halted():
                    print("")
                    print(f"Correct combination: {these_items}")
                    print("")
                    print(message)
                    return

                for item in these_items:
                    self.send_msg(f"drop {item}")

    def get_items(self):
        self.send_msg("inv")
        message = self.execute_str()
        items = self.parse_list(message)
        return items

    def is_blacklisted(self, item):
        return item in [
            "infinite loop",
            "escape pod",
            "molten lava",
            "giant electromagnet",
            "photons",
        ]

    # in: message
    # out: ["north", "east", "west"]
    def parse_directions(self, message):
        dirs = []
        if re.search(r"- east\n", message):
            dirs.append("east")
        if re.search(r"- north\n", message):
            dirs.append("north")
        if re.search(r"- south\n", message):
            dirs.append("south")
        if re.search(r"- west\n", message):
            dirs.append("west")
        return dirs

    # in: message
    # out: [] or ['tambourine']
    def parse_list(self, message):
        return re.findall(r"- (.*?)(?:\n|$)", message)

    def parse_items(self, message):
        item_list = re.findall("Items (?:here|in your inventory):\n(.*)\n\n", message)
        if len(item_list) > 0:
            return self.parse_list(item_list[0])
        return []

    # in: message
    # out: "Hull Breach"
    def parse_title(self, message):
        titles = re.findall(f"== (.*?) ==", message)
        if len(titles) < 1:
            raise ValueError("Couldn't find title of this room")
        return titles[0]

    def part1(self):
        while True:
            print(self.execute_str())
            ins = input(
                "command (w, n, e, s, take item, drop item, or 'solve' to automatically solve)> "
            )
            if ins == "w":
                ins = "west"
            elif ins == "e":
                ins = "east"
            elif ins == "n":
                ins = "north"
            elif ins == "s":
                ins = "south"
            elif ins == "solve":
                self.explore()
                self.pick_up_items()
                self.try_all_items()
                return
            self.send_msg(ins)
        return None

    def num_to_str(self, results):
        return "".join([chr(s) for s in results])

    def string_to_nums(self, string):
        return [ord(s) for s in string]
Example #22
0
 def parse_input(cls, input_str: str):
     return Computer.parse_input(input_str)
Example #23
0
 def spawn_computers(self):
     computers = []
     for i in range(self.how_many):
         cpu = Computer(self.program, [i])
         computers.append(cpu)
     self.computers = computers
Example #24
0
 def __init__(self, program):
     self.program = program
     self.cpu = Computer(self.program, [])
Example #25
0
class Day17Droid:
    def __init__(self, program):
        self.program = program
        self.cpu = Computer(self.program, [])
        self.grid = defaultdict(lambda: 0)
        self.load_pic()

    def load_pic(self):
        result = self.execute()
        location = complex(0, 0)
        for num in result:
            if num == 10:
                new_imag = int(location.imag + 1)
                location = complex(0, new_imag)
            else:
                char = chr(num)
                self.grid[location] = char
                location += complex(1, 0)

    def execute(self):
        self.cpu.execute()
        result = []
        while self.cpu.has_output():
            result.append(self.cpu.pop_output())
        return result

    def display(self):
        reals = [c.real for c in self.grid.keys() if self.grid[c] != 0]
        imags = [c.imag for c in self.grid.keys() if self.grid[c] != 0]
        system("clear")
        for y in range(int(min(imags)) - 2, int(max(imags)) + 3):
            for x in range(int(min(reals)) - 2, int(max(reals)) + 3):
                char = self.grid[complex(x, y)]
                print(char, end="")
            print("")

    def trace_path(self):
        # print("Trace")
        location, direct = self.robot_location()
        steps = []
        steps_taken = 0
        while True:
            if self.grid[location + direct] != "#":
                # print(f"Need to turn {x} {y}")
                if self.grid[location + turn_right(direct)] == "#":
                    steps.append(steps_taken)
                    steps_taken = 0
                    steps.append("R")
                    direct = turn_right(direct)
                elif self.grid[location + turn_left(direct)] == "#":
                    steps.append(steps_taken)
                    steps_taken = 0
                    steps.append("L")
                    direct = turn_left(direct)
                else:
                    steps.append(steps_taken)
                    # print("Done!")
                    break
            else:
                location += direct
                steps_taken += 1

        # Drop first 0
        steps.pop(0)
        steps2 = []
        while len(steps) > 0:
            turn = str(steps.pop(0))
            how_far = str(steps.pop(0))
            steps2.append(turn + how_far)

        return steps2

    # Is there a better way?
    def is_sublist(self, needle, haystack):
        return self.to_str_comma(needle) in self.to_str_comma(haystack)

    def to_str_comma(self, a):
        return ",".join([str(x) for x in a])

    def create_program(self):
        trace = self.trace_path()
        # print("==========")
        # print(trace)
        # print("==========")

        patterns = {}
        pattern_names = ["A", "B", "C"]
        for n in pattern_names:
            patterns[n] = []

            for i, item in enumerate(trace):
                if item in pattern_names:
                    if len(patterns[n]) > 0:
                        break
                    continue
                patterns[n].append(item)
                pattern_length = sum(len(x) + 2 for x in patterns[n]) - 1
                if pattern_length > 20 or not self.is_sublist(
                        patterns[n], trace[i + 1:]):
                    patterns[n].pop()
                    break

            p_str = self.to_str_comma(patterns[n])
            trace_str = self.to_str_comma(trace)
            trace = trace_str.replace(p_str, n).split(",")

        prog = ",".join(trace) + "\n"
        for p in patterns.values():
            prog += ",".join(p).replace("R", "R,").replace("L", "L,") + "\n"

        everything = self.prog_to_ascii(prog) + self.prog_to_ascii("n\n")
        return everything

    def prog_to_ascii(self, string):
        return [ord(s) for s in string]

    def robot_location(self):
        location = complex(-1, -1)
        robot_char = ""
        for x, y in gen_coords(self.grid):
            char = self.grid[complex(x, y)]
            if char == "^" or char == "v" or char == "<" or char == ">":
                location = complex(x, y)
                robot_char = char
                break

        return location, COMPLEX_OF_ROBOTCHAR[robot_char]

    def part1(self):
        intersections = 0
        score = 0
        for x, y in gen_coords(self.grid):
            char = self.grid[complex(x, y)]
            if char != "#":
                continue
            char_n = self.grid[complex(x, y - 1)]
            char_s = self.grid[complex(x, y + 1)]
            char_w = self.grid[complex(x - 1, y)]
            char_e = self.grid[complex(x + 1, y)]
            if char_n == "#" and char_s == "#" and char_w == "#" and char_e == "#":
                intersections += 1
                score += x * y

        return score

    def part2(self):
        prog = self.create_program()

        # Load prog into computer, execute
        cpu = Computer(self.program, [])
        cpu.memory[0] = 2
        for instruction in prog:
            cpu.add_input(instruction)
        cpu.execute()
        result = []
        while cpu.has_output():
            result.append(cpu.pop_output())
        return result[-1]
Example #26
0
 def __init__(self, program):
     self.program = program
     self.cpu = Computer(self.program, [])
     self.grid = defaultdict(lambda: 0)
     self.load_pic()
Example #27
0
def test_execute_program():
    computer = Computer([1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50])
    assert computer.run() == 3500
    assert computer.memory == [3500, 9, 10, 70, 2, 3, 11, 0, 99, 30, 40, 50]