예제 #1
0
def main(puzzle_input):
    computer = Intcode(puzzle_input)
    computer.run_program()
    part1 = sum([
        1 for i in range(2, len(computer.output), 3) if computer.output[i] == 2
    ])

    computer = Intcode(puzzle_input)
    computer.memory[0] = 2
    score = 0
    while not computer.finished:
        computer.output.clear()
        computer.run_program()
        output = computer.output
        for i in range(0, len(output), 3):
            #X=-1, Y=0 -> third is score
            if output[i] == -1 and output[i + 1] == 0:
                score = output[i + 2]
            else:
                #3 is a horizontal paddle tile. The paddle is indestructible.
                if output[i + 2] == 3:
                    paddle_pos = output[i]
                #4 is a ball tile. The ball moves diagonally and bounces off objects.
                elif output[i + 2] == 4:
                    ball_pos = output[i]
        if paddle_pos > ball_pos:
            computer.input.append(-1)
        elif paddle_pos < ball_pos:
            computer.input.append(1)
        else:
            computer.input.append(0)

    return part1, score
예제 #2
0
def amp_to_thruster(phase_set, i_set):
    # Handles amp chaining, returns [signal, [phase_order]]
    resultant_set = [0, []]
    possible_phases = permute(phase_set)

    for phases in possible_phases:
        amps = []
        temp_result = 0
        halted = False
        for phase in phases:
            temp_amp = Computer(i_set.copy(),
                                amp_inputs=[phase, temp_result],
                                pause_on_output=True)
            temp_amp.run_program()
            temp_result = int(temp_amp.output)
            amps.append(temp_amp)

        i = 0

        while not halted:
            amps[i].run_program(amp_inputs=[temp_result])
            halted = amps[i].halted
            if not halted:
                # print(f'amp output: {amps[i].output} - halted? {amps[i].halted}')
                temp_result = int(amps[i].output)
                i += 1
                if i == len(amps):
                    i = 0  # Reset and loop
            # print(f'halted? {halted}')

        if temp_result > resultant_set[0]:
            # print(f'New record: {temp_result} using set {phases}')
            resultant_set = [temp_result, phases]

    return resultant_set
예제 #3
0
def part1(part_input):
    print("PART1")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []
    computer = Intcode(memory, input_buffer, output_buffer)

    # Feed instructions
    instructions = [
        "OR A T",  # Check that A, B or C has a hole
        "AND B T",
        "AND C T",
        "NOT T J",  # If any of ABC is a hole, set JUMP
        "AND D J",  # but only if 4th spot is free
        #
        "WALK",
    ]

    for instruction in instructions:
        for data_input in ascii_to_data(instruction):
            computer.set_input(data_input)
        computer.set_input(ord("\n"))

    computer.run_program()

    if len(computer.output_buffer) > 100:
        print(data_to_ascii(computer.output_buffer))
    else:
        print(data_to_ascii(computer.output_buffer[:-1]))
        print(computer.output_buffer[-1])
예제 #4
0
def test_add_opcode_mixed_1():
    computer = Intcode([1001, 5, 6, 0, 99, 10, 15], None)
    computer.run_program()
    if computer.program[0] == 16:
        assert True
    else:
        assert False
예제 #5
0
def test_mul_opcode_position():
    computer = Intcode([2, 5, 6, 0, 99, 10, 15], None)
    computer.run_program()
    if computer.program[0] == 150:
        assert True
    else:
        assert False
예제 #6
0
def main(puzzle_input):
    part1 = 0
    for phaseSettings in itertools.permutations(range(5)):
        prev_output = [0]
        for phaseSetting in phaseSettings:
            computer = Intcode(puzzle_input)
            computer.input = [phaseSetting, prev_output[0]]
            computer.run_program()
            part1 = max(part1, computer.output[0])
            prev_output = computer.output

    part2 = 0
    computer_count = 5
    for phaseSettings in itertools.permutations(range(5, 10)):
        computers = [Intcode("0") for _ in range(computer_count)]
        for i in range(computer_count):
            computers[i].memory = computer.memory.copy()
            computers[i].output = [phaseSettings[i]]
        for i in range(computer_count):
            computers[i].input = computers[i - 1].output
        computers[0].input.append(0)

        while computers[0].finished == False:
            for i in range(computer_count):
                computers[i].run_program()
        part2 = max(part2, computers[-1].output[0])

    return part1, part2
예제 #7
0
def part1(part_input):
    print("PART1")

    GRID_SIZE = 50

    grid = [[0 for i in range(GRID_SIZE)] for j in range(GRID_SIZE)]

    initial_memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []

    last_point = (0, 0)

    for j in range(len(grid)):
        for i in range(len(grid[0])):
            memory = initial_memory[:]

            computer = Intcode(memory, input_buffer, output_buffer)

            computer.set_input(i)
            computer.set_input(j)

            computer.run_program()

            grid[j][i] = computer.output_buffer.pop()

            if grid[j][i] == 1:
                last_point = (i, j)

    print(sum([sum(row) for row in grid]))

    return last_point
예제 #8
0
def test_mul_opcode_immediate():
    computer = Intcode([1102, 5, 6, 0, 99, 10, 15], None)
    computer.run_program()
    if computer.program[0] == 30:
        assert True
    else:
        assert False
예제 #9
0
def part1(part_input):
    print("PART1")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []
    computer = Intcode(memory, input_buffer, output_buffer)

    computer.run_program()

    output_ascii = list(map(chr, computer.output_buffer))
    output_grid = "".join(output_ascii).split("\n")

    # Detect intersections
    calibration_sum = 0
    for j in range(1, len(output_grid) - 1):
        for i in range(1, len(output_grid[j]) - 1):
            if output_grid[j][i] != "#":
                continue

            if (output_grid[j][i - 1] == "#" and output_grid[j][i + 1] == "#"
                    and output_grid[j - 1][i] == "#"
                    and output_grid[j + 1][i] == "#"):
                calibration_sum += i * j

    print(calibration_sum)
예제 #10
0
def run_program(puzzle_input, noun, verb):
    computer = Intcode(puzzle_input)
    computer.memory[1] = noun
    computer.memory[2] = verb
    computer.run_program()

    return computer.memory[0]
예제 #11
0
def part1(part_input):
    print("PART1")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []
    computer = Intcode(memory, input_buffer, output_buffer)

    # Initialize the droid on an open spot
    nodes = {}
    nodes[(0, 0)] = Node(0, 0, 1)
    droid = nodes[(0, 0)]

    # Run the program until the robot has finished mapping the whole area
    while True:
        movement_command = None
        current_unexplored = droid.get_unexplored_directions()

        # If we find a non-explored neighbor, navigate there
        for test_dir in current_unexplored:
            movement_command = test_dir
            break

        # Check if we need to backtrack
        if len(current_unexplored) == 0 or movement_command is None:
            backtrack_command = droid.get_backtrack_movement()
            if backtrack_command is not None:
                movement_command = backtrack_command

        # If the movement command is still None, every path has been checked
        if movement_command is None:
            break

        # Run the program
        computer.input_buffer.append(movement_command)
        computer.run_program()
        output = computer.output_buffer.pop(0)

        next_position = apply_direction(droid.position, movement_command)
        if next_position not in nodes:
            nodes[next_position] = Node(next_position[0], next_position[1],
                                        output, droid)

            # Update the grid's neighbour relations
            update_neighbors(nodes)

        if output != 0:
            droid = nodes[next_position]

    # Find the shortest path to the oxygen system
    # Starting from the droid's current position (at the starting position)
    # do a A* search updating the depth of all nodes
    droid.set_depth(0)
    for k, v in nodes.items():
        if v.value == 2:
            print(v.depth)
            break

    return nodes
예제 #12
0
def test_mul_opcode_mixed_2():
    computer = Intcode([102, 5, 6, 0, 99, 10, 15], None)
    computer.run_program()
    if computer.program[0] == 75:
        assert True
    else:
        print(computer.program[0])
        assert False
예제 #13
0
def position_in_beam(initial_memory, input_buffer, output_buffer, position):
    memory = initial_memory[:]
    computer = Intcode(memory, input_buffer, output_buffer)
    computer.set_input(position[0])
    computer.set_input(position[1])

    computer.run_program()

    return computer.output_buffer.pop() == 1
예제 #14
0
def manual_game(puzzle_input):
    computer = Intcode(puzzle_input)
    while not computer.finished:
        computer.run_program()
        computer.print_output()
        print(get_doors(computer.get_output_string()))
        print(get_items(computer.get_output_string()))

        computer.add_ascii_input(input())
        computer.output.clear()
    return None, None
예제 #15
0
def part1(part_input):
    print("PART1")

    memory = parse_input_file(part_input)
    input_buffer = [1]
    output_buffer = []

    computer = Intcode(memory, input_buffer, output_buffer)
    computer.run_program()

    print(computer.output_buffer[0])
예제 #16
0
def main(puzzle_input):
    computer = Intcode(puzzle_input)
    computer.input.append(1)
    computer.run_program()
    part1 = computer.output[0]
    
    computer = Intcode(puzzle_input)
    computer.input.append(2)
    computer.run_program()
    part2 = computer.output[0]

    return part1, part2
예제 #17
0
def main(puzzle_input):
    computer = Intcode(puzzle_input)
    computer.input = [1]
    computer.run_program()
    part1 = computer.output[-1]

    computer = Intcode(puzzle_input)
    computer.input = [5]
    computer.run_program()
    part2 = computer.output[0]

    return part1, part2
예제 #18
0
def main(puzzle_input):
    computer = Intcode(puzzle_input)
    computer.run_program()

    grid = []
    inner = []
    for c in computer.output:
        if c == 10:
            if len(inner) > 0:
                grid.append(inner)
                inner = []
        else:
            inner.append(chr(c))
        #print(chr(c), end = '')

    part1 = 0
    for x in range(1, len(grid[0]) - 1):
        for y in range(1, len(grid) - 1):
            if grid[y][x] == "#" and all(
                    grid[y + yy][x + xx] == "#"
                    for (xx, yy) in [(0, -1), (1, 0), (0, 1), (-1, 0)]):
                part1 += x * y

    for x in range(len(grid[0])):
        for y in range(len(grid)):
            if grid[y][x] in "^v<>":
                pos = x + y * 1j
                direction = {"^": -1j, "v": 1j, "<": -1, ">": 1}[grid[y][x]]
                break

    commands = find_commands(pos, direction, grid)
    functions = find_functions(commands, [])
    main_routine = create_main_routine(commands, functions)

    program_input = []
    add_function(program_input, main_routine)
    for function in functions:
        add_function(program_input, ",".join(map(str, function)))
    add_function(program_input, "n")
    #add_function(program_input, "A,B,A,B,A,C,A,C,B,C")
    #add_function(program_input, "R,6,L,10,R,10,R,10")
    #add_function(program_input, "L,10,L,12,R,10")
    #add_function(program_input, "R,6,L,12,L,10")
    #add_function(program_input, "n")

    computer = Intcode(puzzle_input)
    computer.memory[0] = 2
    computer.input = program_input
    computer.run_program()
    part2 = computer.output[-1]

    return part1, part2
예제 #19
0
def part2(part_input):
    print("PART2")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []

    # Set the coin counter
    memory[0] = 2

    computer = Intcode(memory, input_buffer, output_buffer)

    grid = [[0 for i in range(WIDTH)] for j in range(HEIGHT)]

    # Run one step to get the paddle and ball positions
    computer.run_program()
    parse_output(computer, grid)

    paddle = [0, 0]
    ball = [0, 0]

    score = 0
    while True:
        if sum(map(lambda x: x.count(2), grid)) == 0:
            break

        # Update ball and paddle positions
        for j in range(len(grid)):
            for i in range(len(grid[j])):
                if grid[j][i] == 4:
                    ball = [i, j]
                elif grid[j][i] == 3:
                    paddle = [i, j]

        # Check which direction to move the paddle
        if ball[0] == paddle[0]:
            computer.input_buffer.append(0)
        elif ball[0] < paddle[0]:
            computer.input_buffer.append(-1)
        else:
            computer.input_buffer.append(1)

        # Run the program
        computer.run_program()
        score = parse_output(computer, grid)

        # Print the grid
        # print_grid(grid)

    print(score)
예제 #20
0
def part1(part_input):
    print("PART1")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []

    computer = Intcode(memory, input_buffer, output_buffer)

    grid = [[0 for i in range(WIDTH)] for j in range(HEIGHT)]

    computer.run_program()
    parse_output(computer, grid)

    print(sum(map(lambda x: x.count(2), grid)))
예제 #21
0
def manual_game(puzzle_input):
    computer = Intcode(puzzle_input)
    computer.memory[0] = 2
    score = 0
    tiles = {}
    while not computer.finished:
        computer.output.clear()
        computer.run_program()
        output = computer.output
        for i in range(0, len(output), 3):
            #X=-1, Y=0 -> third is score
            if output[i] == -1 and output[i + 1] == 0:
                score = output[i + 2]
            else:
                #0 is an empty tile. No game object appears in this tile.
                if output[i + 2] == 0:
                    char = " "
                #1 is a wall tile. Walls are indestructible barriers.
                elif output[i + 2] == 1:
                    char = "#"
                #2 is a block tile. Blocks can be broken by the ball.
                elif output[i + 2] == 2:
                    char = "*"
                #3 is a horizontal paddle tile. The paddle is indestructible.
                elif output[i + 2] == 3:
                    char = "-"
                #4 is a ball tile. The ball moves diagonally and bounces off objects.
                elif output[i + 2] == 4:
                    char = "O"
                tiles[(output[i], output[i + 1])] = char

        print("Score:", score)
        for y in range(max([x for x, _ in tiles.keys()]) + 1):
            for x in range(max([y for _, y in tiles.keys()]) + 1):
                if (x, y) in tiles:
                    print(tiles[(x, y)], end='')
            print("")

        user_input = input()
        if user_input == "a":
            computer.input.append(-1)
        if user_input == "d":
            computer.input.append(1)
        if user_input == " ":
            computer.input.append(0)
    return None, None
예제 #22
0
def part2(part_input):
    print("PART2")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []
    computer = Intcode(memory, input_buffer, output_buffer)

    # Active mode
    # computer.set_memory(0, 2)

    computer.run_program()

    output_ascii = list(map(chr, computer.output_buffer))
    output_grid = "".join(output_ascii).split("\n")

    for row in output_grid:
        print(row)
예제 #23
0
def part2(part_input):
    print("PART2")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []
    computer = Intcode(memory, input_buffer, output_buffer)

    # Feed instructions
    instructions = [
        # Part 1
        "OR A T",  # Check that A, B or C has a hole
        "AND B T",
        "AND C T",
        "NOT T J",  # If any of ABC is a hole, set JUMP
        "AND D J",  # but only if 4th spot is free
        # Part 2
        # Jump only if we can jump immediately (H),
        # or after 1 step (E and I),
        # or if 2nd step is possible too (E and F)
        # ->
        # H or (E and I) or (E and F) ->
        # H or (E and (I or F))
        "OR I T",
        "OR F T",
        "AND E T",
        "OR H T",
        "AND T J",
        #
        "RUN",
    ]

    for instruction in instructions:
        for data_input in ascii_to_data(instruction):
            computer.set_input(data_input)
        computer.set_input(ord("\n"))

    computer.run_program()

    if len(computer.output_buffer) > 100:
        print(data_to_ascii(computer.output_buffer))
    else:
        print(data_to_ascii(computer.output_buffer[:-1]))
        print(computer.output_buffer[-1])
예제 #24
0
def main(puzzle_input):
    computer = Intcode(puzzle_input)

    program_input = []
    add_function(program_input, "NOT C J")
    add_function(program_input, "AND D J")
    add_function(program_input, "NOT A T")
    add_function(program_input, "OR T J")
    add_function(program_input, "WALK")
    computer.input = program_input
    computer.run_program()

    for c in computer.output:
        if c >= 256:
            part1 = c
            break
    
    # ABC[D]EFG[H]I
    program_input = []
    
    # Hole in A or B or C
    add_function(program_input, "NOT A J") 
    add_function(program_input, "NOT B T") 
    add_function(program_input, "OR T J") 
    add_function(program_input, "NOT C T")
    add_function(program_input, "OR T J")

    # Ground in D and (H or (E and I))
    add_function(program_input, "AND D J")
    add_function(program_input, "OR I T")
    add_function(program_input, "AND E T")  
    add_function(program_input, "OR H T")
    add_function(program_input, "AND T J") 
    add_function(program_input, "RUN")

    computer = Intcode(puzzle_input)
    computer.input = program_input
    computer.run_program()
    for c in computer.output:
        if c >= 256:
            part2 = c
            break
    
    return part1, part2
예제 #25
0
def calculate_paint(puzzle_input, paint):
    xmin = ymin = float("inf")
    xmax = ymax = -float("inf")
    pos = 0
    facing = -1j

    computer = Intcode(puzzle_input)
    while not computer.finished:
        computer.output.clear()
        computer.input.append(paint[pos])
        computer.run_program()
        paint[pos] = computer.output[0]
        facing *= (1j if computer.output[1] == 1 else -1j)
        pos += facing
        xmin = min(xmin, pos.real)
        xmax = max(xmax, pos.real)
        ymin = min(ymin, pos.imag)
        ymax = max(ymax, pos.imag)
    return int(xmin), int(xmax), int(ymin), int(ymax)
예제 #26
0
def main(puzzle_input):
    network = []
    for address in range(50):
        computer = Intcode(puzzle_input)
        computer.input.append(address)
        computer.run_program()
        network.append(computer)

    part1 = False
    previous_nat_y = 0
    while True:
        is_idle = True
        for address in range(50):
            computer = network[address]
            if len(computer.input) == 0:
                computer.input.append(-1)
            else:
                is_idle = False

            computer.run_program()

            for index in range(0, len(computer.output), 3):
                if computer.output[index] == 255:
                    nat_value = (computer.output[index + 1],
                                 computer.output[index + 2])
                    if not part1:
                        part1 = nat_value[1]
                else:
                    target = network[computer.output[index]]
                    target.input.append(computer.output[index + 1])
                    target.input.append(computer.output[index + 2])
            computer.output.clear()

        if is_idle:
            if nat_value[1] == previous_nat_y:
                part2 = previous_nat_y
                break
            else:
                previous_nat_y = nat_value[1]
            network[0].input.append(nat_value[0])
            network[0].input.append(nat_value[1])

    return part1, part2
예제 #27
0
def part1(part_input):
    print("PART1")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []
    computer = Intcode(memory, input_buffer, output_buffer)

    while True:
        computer.run_program()
        print(data_to_ascii(computer.output_buffer))

        command = input()
        if command == "exit":
            return

        data = ascii_to_data(command)
        for code in data:
            computer.set_input(code)
        computer.set_input(ord("\n"))
예제 #28
0
def part2(part_input):
    print("PART2")

    memory = parse_input_file(part_input)
    input_buffer = []
    output_buffer = []

    computer = Intcode(memory, input_buffer, output_buffer)

    grid = [[0 for i in range(100)] for j in range(100)]

    robot_pos = (len(grid) // 2, len(grid) // 2)

    grid[robot_pos[1]][robot_pos[0]] = 1

    robot_dir = 0
    dir_lookup = [(0, -1), (1, 0), (0, 1), (-1, 0)]

    visited = set()

    while True:
        step_x, step_y = robot_pos
        step_input = grid[step_y][step_x]
        input_buffer.append(step_input)

        exit_code = computer.run_program()
        if exit_code is None:
            break

        next_color = output_buffer.pop(0)
        next_dir = output_buffer.pop(0)

        visited.add(robot_pos)
        grid[step_y][step_x] = next_color
        next_dir = next_dir * 2 - 1
        robot_dir = (robot_dir + next_dir) % 4
        move_offset = dir_lookup[robot_dir]
        robot_pos = (robot_pos[0] + move_offset[0],
                     robot_pos[1] + move_offset[1])

    print(len(visited))

    for row in grid:
        row_str = ['.' if item == 0 else '#' for item in row]
        print(''.join(row_str))
예제 #29
0
def main(puzzle_input):
    part1 = 0
    for y in range(50):
        for x in range(50):
            computer = Intcode(puzzle_input)
            computer.input = [x, y]
            computer.run_program()
            part1 += computer.output[0]

    left = 0
    right = []
    y = 5
    while True:
        for x in range(left, left + 100):    
            computer = Intcode(puzzle_input)
            computer.input = [x, y]
            computer.run_program()
            if computer.output[0] == 1:
                left = x
                break
        if len(right) == 0:
            right.append(left)
        for x in range(right[-1], right[-1] + 100):
            computer = Intcode(puzzle_input)
            computer.input = [x, y]
            computer.run_program()
            if computer.output[0] == 0:
                right.append(x - 1)
                break
        if len(right) > 100:
            if right[-100] - 99 >= left:
                part2 = left * 10000 + y - 99
                break
        y += 1
    
    return part1, part2
예제 #30
0
def main(puzzle_input):
    #north (1), south (2), west (3), and east (4).
    dir_input = {
        ( 0,-1): 1,
        ( 0, 1): 2,
        (-1, 0): 3,
        ( 1, 0): 4,
    }
    open_stack = list(dir_input.keys())
    area = defaultdict(lambda : -1)
    pos = (0, 0)
    area[pos] = 1
    computer = Intcode(puzzle_input)
    while len(open_stack) > 0:
        pathList = astar.astar(area, pos, open_stack.pop())[1:]

        for path in pathList:
            if path in open_stack:
                open_stack.remove(path)

            direction = dir_input[(path[0] - pos[0], path[1] - pos[1])]
            computer.output.clear()
            computer.input.append(direction)
            computer.run_program()
            
            area[path] = computer.output[0]
            #0: The repair droid hit a wall. Its position has not changed.
            if computer.output[0] == 0:
                pathList.clear()
            #1: The repair droid has moved one step in the requested direction.
            elif computer.output[0] == 1:
                pos = path
            #2: The repair droid has moved one step in the requested direction; its new position is the location of the oxygen system.
            elif computer.output[0] == 2:
                oxygen_pos = path
                pos = path

            for test_dir in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
                test_pos = (pos[0] + test_dir[0], pos[1] + test_dir[1])
                if area[test_pos] == -1 and test_pos not in open_stack:
                    open_stack.append(test_pos)

    #printGrid(area, pos)
    part1 = len(astar.astar(area, (0, 0), oxygen_pos)) - 1
    
    next_open_set = set()
    next_open_set.add(oxygen_pos)
    closed_set = set()
    part2 = -1
    while len(next_open_set) > 0 and len(next_open_set) < 2000:
        part2 += 1
        open_set = next_open_set
        next_open_set = set()
        for pos in open_set:
            closed_set.add(pos)
            for test_dir in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
                test_pos = (pos[0] + test_dir[0], pos[1] + test_dir[1])
                if area[(test_pos[0], test_pos[1])] <= 0:
                    continue
                if test_pos in closed_set or test_pos in open_set or test_pos in next_open_set:
                    continue
                next_open_set.add(test_pos)

    return part1, part2