Example #1
0
def fit(codes: DefaultDict[int, int], width, height: int) -> int:
    """find position in tractor beam that will fit our width and height

    Arguments:
        codes {DefaultDict[int, int]} -- intcode machine instructions
        width {[type]} -- min x area
        height {int} -- min y area

    Returns:
        int -- computed value based on top left area we can fit in
    """
    tractor_bottom_left = TractorInput()
    tractor_bottom_left.current_x = 1
    tractor_bottom_left.current_y = height
    tractor_top_right = TractorInput()

    while True:
        beam_bottom_left = process(copy.copy(codes),
                                   tractor_bottom_left.inputs)
        bottom_status = next(beam_bottom_left)
        if bottom_status:
            tractor_top_right.current_x = tractor_bottom_left.current_x + width - 1
            tractor_top_right.current_y = tractor_bottom_left.current_y - height + 1
            beam_top_right = process(copy.copy(codes),
                                     tractor_top_right.inputs)
            top_status = next(beam_top_right)
            if top_status:
                break
            tractor_bottom_left.current_y += 1

        tractor_bottom_left.current_x += 1

    return tractor_bottom_left.current_x * 10000 + tractor_top_right.current_y
Example #2
0
def alignment_parameter(codes: DefaultDict[int, int]) -> int:
    """calculate the alightment parameters

    Arguments:
        codes {DefaultDict[int, int]} -- intcode machine instructions

    Returns:
        int -- calculated value
    """
    scaffold = set()
    top = 0
    left = 0
    for code in process(codes):
        if code == POUND:
            position = (top, left)
            scaffold.add(position)

        if code == NEW_LINE:
            top += 1
            left = 0
        else:
            left += 1

    total = 0
    for position in get_intersections(scaffold):
        top, left = position
        total += top * left

    return total
Example #3
0
def hull_damage(codes: DefaultDict[int, int], inputs: list = None) -> int:
    """hull damage report.  given valid spring droid inputs bot will report
    hull damage.  Otherwise it will output if the droid is stuck in a hole.

    Arguments:
        codes {DefaultDict[int, int]} -- intcode instructions

    Keyword Arguments:
        inputs {list} -- spring board instructions, if not given user will be prompted

    Returns:
        int -- [description]
    """
    if inputs:
        droid = SpringDroid(collections.deque(inputs))
    else:
        droid = SpringDroid()

    droid_logic = process(codes, droid.droid_input)

    outputs = []
    for output in droid_logic:
        if output > 255:
            return output

        if output == 10:
            print("".join(outputs))
            outputs = []
        else:
            outputs.append(chr(output))
Example #4
0
def tractor_beam(codes: DefaultDict[int, int], max_y: int, max_x: int) -> int:
    """count area effected by tractor beam

    Arguments:
        codes {DefaultDict[int, int]} -- intcode machine instructions
        max_y {int} -- area max y we are considering
        max_x {int} -- area max x we are considering

    Returns:
        int -- total count
    """
    tractor_input = TractorInput()

    total = 0

    start_x = 0
    min_row_count = 1
    current_row_count = 0

    first_x = True
    output = []
    while tractor_input.current_y < max_y:
        beam = process(copy.copy(codes), tractor_input.inputs)
        for status in beam:
            if status == 1:
                if first_x:
                    start_x = tractor_input.current_x + 1
                    first_x = False
                    repeat_count = min(min_row_count,
                                       max_x - tractor_input.current_x)
                    output += ["#"] * repeat_count
                    current_row_count += repeat_count
                    tractor_input.current_x += repeat_count - 1

                else:
                    output.append("#")
                    current_row_count += 1
            else:
                output.append(".")

            if tractor_input.current_x >= start_x + int(min_row_count * 1.25) \
                    or tractor_input.current_x >= max_x:
                print("".join(output))
                if current_row_count == 0:
                    return total
                tractor_input.current_x = start_x
                output = ["."] * start_x

                tractor_input.current_y += 1
                first_x = True
                min_row_count = max(min_row_count, current_row_count)
                total += current_row_count
                current_row_count = 0
            else:
                tractor_input.current_x += 1
def paint(codes: DefaultDict[int, int],
          painted: Dict[tuple, int] = None) -> Dict[tuple, int]:
    """read paint instructions from intcode computer with provided inputs

    Arguments:
        codes {DefaultDict[int, int]} -- intcode inputs,
                                         this will output the robots paint instructions

    Keyword Arguments:
        painted {Dict[tuple, int]} -- initial haul paint (default: {None})
                                      coords not given are assumed painted

    Returns:
        Dict[tuple, int] -- haul paint
    """
    # init painted dictionary
    if painted is None:
        painted = {}

    direction = 0

    # start intcode machine
    result = process(codes)

    position = (0, 0)
    for _ in result:
        _ok = result.send(painted.get(position, BLACK))

        color = next(result)
        painted[position] = color

        turn = next(result)

        # turn
        if turn == TURN_RIGHT:
            direction += 0.25
            if direction == 1:
                direction = 0
        elif turn == TURN_LEFT:
            direction -= 0.25
            if direction == -0.25:
                direction = 0.75
        else:
            ValueError("Invalid turn: {turn}")

        # move forward based on direction
        if direction == UP:
            position = (position[0] - 1, position[1])
        elif direction == RIGHT:
            position = (position[0], position[1] + 1)
        elif direction == DOWN:
            position = (position[0] + 1, position[1])
        elif direction == LEFT:
            position = (position[0], position[1] - 1)
    return painted
def part_02(input_path):
    """Part 2"""
    with open(input_path) as file_input:
        codes = read_codes(file_input)

    processing = process(codes)
    next(processing)
    _ok = processing.send(5)

    for output in processing:
        print(output)
def part_01(input_path, noun, verb):
    """Part 1"""
    with open(input_path) as file_input:
        codes = read_codes(file_input)

    # replace positions 1 and 2
    codes[1] = noun
    codes[2] = verb

    processing = process(codes)
    for _ in processing:
        pass

    print(f"result is {codes[0]}")
Example #8
0
def run(codes: DefaultDict[int, int], phase: int = None):
    """run given input with provided phase

    Arguments:
        codes {DefaultDict[int, int]} -- instruction set

    Keyword Arguments:
        phase {int} -- optinal input (default: {None})
    """
    boosting = process(codes)

    if phase is not None:
        next(boosting)
        _ok = boosting.send(phase)

    for output in boosting:
        print(output)
def count_block(codes: DefaultDict[int, int]) -> int:
    """count all BLOCK tiles

    Arguments:
        codes {DefaultDict[int, int]} -- intcode instructions

    Returns:
        int -- total block tiles
    """
    board = {}
    game = process(codes)

    for left in game:
        top = next(game)
        tile = next(game)
        board[(top, left)] = tile

    count = collections.Counter(board.values())
    return count[BLOCK]
Example #10
0
def part_02(input_path, target):
    """Part 2"""
    with open(input_path) as file_input:
        init_codes = read_codes(file_input)

    # loop through each possible noun and verb (0-99)
    for noun in range(100):
        for verb in range(100):
            codes = copy.copy(init_codes)
            # update starting "noun" and "verb"
            codes[1] = noun
            codes[2] = verb

            processing = process(codes)
            for _ in processing:
                pass

            if codes[0] == target:
                print(f"100 * {noun} + {verb} = {100 * noun + verb}")
                return
Example #11
0
def amp_checks(codes: DefaultDict[int, int], phase_settings: List[int]) -> int:
    """check all possible phase settings for optimal settings for amplifiers

    Arguments:
        codes {DefaultDict[int, int]} -- original list of codes to start on each amp
        phase_settings {List[int]} -- known phase settings (not in a particular order)

    Returns:
        int -- returns the largest possible output with known phase settings
    """

    # list of every result from all sequences
    results = []

    sequences = itertools.permutations(phase_settings)

    for sequence in sequences:
        last_output = 0
        amps = []
        for phase_setting in sequence:
            # run through amp with a phase settings and last output from previous amp
            amp_codes = codes.copy()
            amp = process(amp_codes)
            next(amp)
            _ok = amp.send(phase_setting)
            amps.append(amp)

        last_output = 0
        try:
            while True:
                for amp in amps:
                    next(amp)
                    _ok = amp.send(last_output)
                    last_output = next(amp)
        except StopIteration:
            pass
        results.append(last_output)

    return max(results)
    def run(self):
        """network loop, when output exists
        send to existing machine on the network"""
        try:
            machine = process(copy.copy(self.codes), self.packet_input)
            while True:
                address = next(machine)
                x_portion = next(machine)
                y_portion = next(machine)
                self.is_idle = False

                # unknown network address
                if address not in self.network:
                    return address, x_portion, y_portion

                # queue output to proper machine
                network_manager = self.network[address]
                # recieved input, not idle
                network_manager.is_idle = False
                network_manager.packets.put((x_portion, y_portion))

        except NetworkHalt:
            pass
Example #13
0
def play(codes: DefaultDict[int, int], is_human: bool):
    """play the game!

    Arguments:
        codes {DefaultDict[int, int]} -- intcode instructions
        is_human {bool} -- read in user input if true (fun, but very...slow...)
    """
    screen = curses.initscr()
    curses.noecho()
    curses.cbreak()
    curses.curs_set(False)
    screen.keypad(True)

    steps = 0
    max_height = 0
    max_width = 0
    paddle = (0, 0)
    ball = (0, 0)

    # for user inputs
    def draw_input():
        screen.refresh()
        key = screen.getch()
        if key == curses.KEY_LEFT:
            return -1
        if key == curses.KEY_RIGHT:
            return 1
        return 0

    # for automatic inputs
    def draw_ai():
        screen.refresh()
        if paddle[1] == ball[1]:
            return 0

        if paddle[1] > ball[1]:
            return -1

        return 1

    if is_human:
        game = process(codes, draw_input)
    else:
        game = process(codes, draw_ai)

    try:
        for left in game:
            steps += 1
            top = next(game)
            position = (top, left)

            max_width = max(max_width, left)
            max_height = max(max_height, top)

            if position == (0, -1):
                score = next(game)
                screen.addstr(max_height + 1, 0, f"Score: {score}")
            else:
                tile = next(game)
                if tile == BALL:
                    ball = position
                elif tile == PADDLE:
                    paddle = position
                screen.addstr(top, left, TILE_OUTPUT[tile])

        message_1 = "Game Complete!"
        message_2 = "Press Any Key to Exit..."
        screen.addstr(max_height // 2, max_width // 2 -
                      len(message_1) // 2, message_1)
        screen.addstr(max_height // 2 + 1, max_width //
                      2 - len(message_2) // 2, message_2)
        screen.refresh()
        screen.getch()
    except curses.error:
        print("Please resize the terminal in order to run the game!")
    finally:
        curses.endwin()
Example #14
0
 def init_map(self):
     """initialize the map state by traversing to the furthest unknown area"""
     self.state = process(copy.copy(self.codes), self._blind_input)
     self._run()
Example #15
0
def visit_all(codes: DefaultDict[int, int]) -> int:
    """visit all locations and gather dust

    Arguments:
        codes {DefaultDict[int, int]} -- intcode machine instructions

    Returns:
        int -- total dust collected
    """
    # init values
    bot_position = None
    bot_facing = None
    scaffold = set()
    visited = set()
    top = 0
    left = 0
    line = []
    for code in process(codes.copy()):
        if code == POUND:
            position = (top, left)
            scaffold.add(position)
        elif code in BOT_CODE:
            bot_position = (top, left)
            scaffold.add(bot_position)
            visited.add(bot_position)
            bot_facing = code

        if code == NEW_LINE:
            top += 1
            left = 0
            print(''.join(line))
            line = []
        else:
            left += 1
            line.append(chr(code))

    # get direcions, it appears output does not have intersections at "corners"
    # so logic should be "turn" then move forward until end of straight away
    # then find the next "turn" and repeat until the end
    directions = []
    bot_facing, direction = bot_turn(bot_facing, bot_position, scaffold)
    while bot_facing:
        # updates visited scaffolds
        bot_position, moved = bot_move(bot_facing, bot_position, scaffold,
                                       visited)
        directions.append(f"{direction} {moved}")
        bot_facing, direction = bot_turn(bot_facing, bot_position, scaffold)

    # check that all scaffolds have been visited
    assert scaffold == visited, "Not all positions have been visited"

    # once we determine the full path, we need to compress this into shorter instructions
    main, func_a, func_b, func_c = compress_directions(directions)

    def input_gen(actions):
        for action in ",".join(actions):
            yield ord(action)
        yield NEW_LINE

    main = input_gen(main)

    func_a = input_gen(map(lambda value: value.replace(" ", ","), func_a))
    func_b = input_gen(map(lambda value: value.replace(" ", ","), func_b))
    func_c = input_gen(map(lambda value: value.replace(" ", ","), func_c))

    def display_prompt():
        yield ord("n")
        yield NEW_LINE

    display_prompt = display_prompt()

    def direction_input():
        for value in main:
            return value

        for value in func_a:
            return value

        for value in func_b:
            return value

        for value in func_c:
            return value

        for value in display_prompt:
            return value

    # wake bot up
    codes[0] = 2

    bot_directions = process(codes, direction_input)

    output = 0
    for output in bot_directions:
        pass

    return output