Add solution to day 17 part 2

This commit is contained in:
Nick Krichevsky 2019-12-19 23:57:19 -05:00
parent 9daef0a6ea
commit cbb376667a
2 changed files with 267 additions and 7 deletions

View file

@ -1,2 +1 @@
1,330,331,332,109,3890,1102,1,1182,16,1102,1471,1,24,101,0,0,570,1006,570,36,1002,571,1,0,1001,570,-1,570,1001,24,1,24,1105,1,18,1008,571,0,571,1001,16,1,16,1008,16,1471,570,1006,570,14,21102,58,1,0,1105,1,786,1006,332,62,99,21102,333,1,1,21102,73,1,0,1105,1,579,1102,0,1,572,1102,1,0,573,3,574,101,1,573,573,1007,574,65,570,1005,570,151,107,67,574,570,1005,570,151,1001,574,-64,574,1002,574,-1,574,1001,572,1,572,1007,572,11,570,1006,570,165,101,1182,572,127,101,0,574,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1105,1,81,21102,1,340,1,1106,0,177,21102,1,477,1,1106,0,177,21101,0,514,1,21101,0,176,0,1105,1,579,99,21101,184,0,0,1106,0,579,4,574,104,10,99,1007,573,22,570,1006,570,165,102,1,572,1182,21101,375,0,1,21101,0,211,0,1105,1,579,21101,1182,11,1,21102,1,222,0,1106,0,979,21102,1,388,1,21101,0,233,0,1106,0,579,21101,1182,22,1,21102,244,1,0,1105,1,979,21102,401,1,1,21102,1,255,0,1106,0,579,21101,1182,33,1,21101,266,0,0,1105,1,979,21102,1,414,1,21102,277,1,0,1105,1,579,3,575,1008,575,89,570,1008,575,121,575,1,575,570,575,3,574,1008,574,10,570,1006,570,291,104,10,21101,0,1182,1,21101,313,0,0,1105,1,622,1005,575,327,1101,0,1,575,21102,327,1,0,1105,1,786,4,438,99,0,1,1,6,77,97,105,110,58,10,33,10,69,120,112,101,99,116,101,100,32,102,117,110,99,116,105,111,110,32,110,97,109,101,32,98,117,116,32,103,111,116,58,32,0,12,70,117,110,99,116,105,111,110,32,65,58,10,12,70,117,110,99,116,105,111,110,32,66,58,10,12,70,117,110,99,116,105,111,110,32,67,58,10,23,67,111,110,116,105,110,117,111,117,115,32,118,105,100,101,111,32,102,101,101,100,63,10,0,37,10,69,120,112,101,99,116,101,100,32,82,44,32,76,44,32,111,114,32,100,105,115,116,97,110,99,101,32,98,117,116,32,103,111,116,58,32,36,10,69,120,112,101,99,116,101,100,32,99,111,109,109,97,32,111,114,32,110,101,119,108,105,110,101,32,98,117,116,32,103,111,116,58,32,43,10,68,101,102,105,110,105,116,105,111,110,115,32,109,97,121,32,98,101,32,97,116,32,109,111,115,116,32,50,48,32,99,104,97,114,97,99,116,101,114,115,33,10,94,62,118,60,0,1,0,-1,-1,0,1,0,0,0,0,0,0,1,32,0,0,109,4,2101,0,-3,586,21002,0,1,-1,22101,1,-3,-3,21101,0,0,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1105,1,597,109,-4,2105,1,0,109,5,1201,-4,0,630,20102,1,0,-2,22101,1,-4,-4,21102,0,1,-3,2208,-3,-2,570,1005,570,781,2201,-4,-3,652,21001,0,0,-1,1208,-1,-4,570,1005,570,709,1208,-1,-5,570,1005,570,734,1207,-1,0,570,1005,570,759,1206,-1,774,1001,578,562,684,1,0,576,576,1001,578,566,692,1,0,577,577,21102,1,702,0,1105,1,786,21201,-1,-1,-1,1106,0,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21101,0,731,0,1106,0,786,1105,1,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21102,756,1,0,1106,0,786,1106,0,774,21202,-1,-11,1,22101,1182,1,1,21101,774,0,0,1106,0,622,21201,-3,1,-3,1105,1,640,109,-5,2105,1,0,109,7,1005,575,802,21001,576,0,-6,20101,0,577,-5,1105,1,814,21102,1,0,-1,21101,0,0,-5,21101,0,0,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,41,-3,22201,-6,-3,-3,22101,1471,-3,-3,1202,-3,1,843,1005,0,863,21202,-2,42,-4,22101,46,-4,-4,1206,-2,924,21102,1,1,-1,1105,1,924,1205,-2,873,21101,35,0,-4,1106,0,924,2102,1,-3,878,1008,0,1,570,1006,570,916,1001,374,1,374,2101,0,-3,895,1102,1,2,0,1201,-3,0,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,922,20101,0,0,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,41,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,59,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1101,0,1,575,21101,0,973,0,1106,0,786,99,109,-7,2106,0,0,109,6,21102,0,1,-4,21101,0,0,-3,203,-2,22101,1,-3,-3,21208,-2,82,-1,1205,-1,1030,21208,-2,76,-1,1205,-1,1037,21207,-2,48,-1,1205,-1,1124,22107,57,-2,-1,1205,-1,1124,21201,-2,-48,-2,1105,1,1041,21102,1,-4,-2,1106,0,1041,21102,-5,1,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,1202,-2,1,0,203,-2,22101,1,-3,-3,21207,-2,48,-1,1205,-1,1107,22107,57,-2,-1,1205,-1,1107,21201,-2,-48,-2,2201,-5,-4,1090,20102,10,0,-1,22201,-2,-1,-2,2201,-5,-4,1103,2101,0,-2,0,1106,0,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1105,1,989,21102,1,439,1,1105,1,1150,21101,477,0,1,1106,0,1150,21102,1,514,1,21101,1149,0,0,1105,1,579,99,21101,1157,0,0,1106,0,579,204,-2,104,10,99,21207,-3,22,-1,1206,-1,1138,2101,0,-5,1176,1202,-4,1,0,109,-6,2105,1,0,32,5,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,30,11,30,1,40,1,40,1,30,13,38,1,1,1,26,5,7,1,1,1,26,1,3,1,7,1,1,1,26,1,3,1,7,1,1,1,26,1,3,1,7,1,1,1,26,1,3,1,7,1,1,1,1,11,14,1,3,1,7,1,1,1,1,1,9,1,14,1,3,1,7,13,1,1,14,1,3,1,9,1,1,1,7,1,1,1,14,1,3,1,9,13,14,1,3,1,11,1,7,1,12,13,3,13,12,1,3,1,3,1,3,1,3,1,3,1,12,13,3,13,12,1,7,1,11,1,3,1,16,1,7,1,11,1,3,1,16,1,7,1,11,1,3,1,16,13,7,1,3,1,24,1,3,1,7,1,3,1,14,11,3,1,7,1,3,1,14,1,13,1,7,1,3,1,14,1,13,1,7,1,3,1,14,1,13,1,7,1,3,1,14,1,13,1,7,5,14,1,13,1,26,1,13,1,26,1,13,1,26,1,13,1,26,1,13,1,26,1,3,11,26,1,3,1,36,9,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,5,32 1,330,331,332,109,3890,1102,1,1182,16,1102,1471,1,24,101,0,0,570,1006,570,36,1002,571,1,0,1001,570,-1,570,1001,24,1,24,1105,1,18,1008,571,0,571,1001,16,1,16,1008,16,1471,570,1006,570,14,21102,58,1,0,1105,1,786,1006,332,62,99,21102,333,1,1,21102,73,1,0,1105,1,579,1102,0,1,572,1102,1,0,573,3,574,101,1,573,573,1007,574,65,570,1005,570,151,107,67,574,570,1005,570,151,1001,574,-64,574,1002,574,-1,574,1001,572,1,572,1007,572,11,570,1006,570,165,101,1182,572,127,101,0,574,0,3,574,101,1,573,573,1008,574,10,570,1005,570,189,1008,574,44,570,1006,570,158,1105,1,81,21102,1,340,1,1106,0,177,21102,1,477,1,1106,0,177,21101,0,514,1,21101,0,176,0,1105,1,579,99,21101,184,0,0,1106,0,579,4,574,104,10,99,1007,573,22,570,1006,570,165,102,1,572,1182,21101,375,0,1,21101,0,211,0,1105,1,579,21101,1182,11,1,21102,1,222,0,1106,0,979,21102,1,388,1,21101,0,233,0,1106,0,579,21101,1182,22,1,21102,244,1,0,1105,1,979,21102,401,1,1,21102,1,255,0,1106,0,579,21101,1182,33,1,21101,266,0,0,1105,1,979,21102,1,414,1,21102,277,1,0,1105,1,579,3,575,1008,575,89,570,1008,575,121,575,1,575,570,575,3,574,1008,574,10,570,1006,570,291,104,10,21101,0,1182,1,21101,313,0,0,1105,1,622,1005,575,327,1101,0,1,575,21102,327,1,0,1105,1,786,4,438,99,0,1,1,6,77,97,105,110,58,10,33,10,69,120,112,101,99,116,101,100,32,102,117,110,99,116,105,111,110,32,110,97,109,101,32,98,117,116,32,103,111,116,58,32,0,12,70,117,110,99,116,105,111,110,32,65,58,10,12,70,117,110,99,116,105,111,110,32,66,58,10,12,70,117,110,99,116,105,111,110,32,67,58,10,23,67,111,110,116,105,110,117,111,117,115,32,118,105,100,101,111,32,102,101,101,100,63,10,0,37,10,69,120,112,101,99,116,101,100,32,82,44,32,76,44,32,111,114,32,100,105,115,116,97,110,99,101,32,98,117,116,32,103,111,116,58,32,36,10,69,120,112,101,99,116,101,100,32,99,111,109,109,97,32,111,114,32,110,101,119,108,105,110,101,32,98,117,116,32,103,111,116,58,32,43,10,68,101,102,105,110,105,116,105,111,110,115,32,109,97,121,32,98,101,32,97,116,32,109,111,115,116,32,50,48,32,99,104,97,114,97,99,116,101,114,115,33,10,94,62,118,60,0,1,0,-1,-1,0,1,0,0,0,0,0,0,1,32,0,0,109,4,2101,0,-3,586,21002,0,1,-1,22101,1,-3,-3,21101,0,0,-2,2208,-2,-1,570,1005,570,617,2201,-3,-2,609,4,0,21201,-2,1,-2,1105,1,597,109,-4,2105,1,0,109,5,1201,-4,0,630,20102,1,0,-2,22101,1,-4,-4,21102,0,1,-3,2208,-3,-2,570,1005,570,781,2201,-4,-3,652,21001,0,0,-1,1208,-1,-4,570,1005,570,709,1208,-1,-5,570,1005,570,734,1207,-1,0,570,1005,570,759,1206,-1,774,1001,578,562,684,1,0,576,576,1001,578,566,692,1,0,577,577,21102,1,702,0,1105,1,786,21201,-1,-1,-1,1106,0,676,1001,578,1,578,1008,578,4,570,1006,570,724,1001,578,-4,578,21101,0,731,0,1106,0,786,1105,1,774,1001,578,-1,578,1008,578,-1,570,1006,570,749,1001,578,4,578,21102,756,1,0,1106,0,786,1106,0,774,21202,-1,-11,1,22101,1182,1,1,21101,774,0,0,1106,0,622,21201,-3,1,-3,1105,1,640,109,-5,2105,1,0,109,7,1005,575,802,21001,576,0,-6,20101,0,577,-5,1105,1,814,21102,1,0,-1,21101,0,0,-5,21101,0,0,-6,20208,-6,576,-2,208,-5,577,570,22002,570,-2,-2,21202,-5,41,-3,22201,-6,-3,-3,22101,1471,-3,-3,1202,-3,1,843,1005,0,863,21202,-2,42,-4,22101,46,-4,-4,1206,-2,924,21102,1,1,-1,1105,1,924,1205,-2,873,21101,35,0,-4,1106,0,924,2102,1,-3,878,1008,0,1,570,1006,570,916,1001,374,1,374,2101,0,-3,895,1102,1,2,0,1201,-3,0,902,1001,438,0,438,2202,-6,-5,570,1,570,374,570,1,570,438,438,1001,578,558,922,20101,0,0,-4,1006,575,959,204,-4,22101,1,-6,-6,1208,-6,41,570,1006,570,814,104,10,22101,1,-5,-5,1208,-5,59,570,1006,570,810,104,10,1206,-1,974,99,1206,-1,974,1101,0,1,575,21101,0,973,0,1106,0,786,99,109,-7,2106,0,0,109,6,21102,0,1,-4,21101,0,0,-3,203,-2,22101,1,-3,-3,21208,-2,82,-1,1205,-1,1030,21208,-2,76,-1,1205,-1,1037,21207,-2,48,-1,1205,-1,1124,22107,57,-2,-1,1205,-1,1124,21201,-2,-48,-2,1105,1,1041,21102,1,-4,-2,1106,0,1041,21102,-5,1,-2,21201,-4,1,-4,21207,-4,11,-1,1206,-1,1138,2201,-5,-4,1059,1202,-2,1,0,203,-2,22101,1,-3,-3,21207,-2,48,-1,1205,-1,1107,22107,57,-2,-1,1205,-1,1107,21201,-2,-48,-2,2201,-5,-4,1090,20102,10,0,-1,22201,-2,-1,-2,2201,-5,-4,1103,2101,0,-2,0,1106,0,1060,21208,-2,10,-1,1205,-1,1162,21208,-2,44,-1,1206,-1,1131,1105,1,989,21102,1,439,1,1105,1,1150,21101,477,0,1,1106,0,1150,21102,1,514,1,21101,1149,0,0,1105,1,579,99,21101,1157,0,0,1106,0,579,204,-2,104,10,99,21207,-3,22,-1,1206,-1,1138,2101,0,-5,1176,1202,-4,1,0,109,-6,2105,1,0,32,5,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,30,11,30,1,40,1,40,1,30,13,38,1,1,1,26,5,7,1,1,1,26,1,3,1,7,1,1,1,26,1,3,1,7,1,1,1,26,1,3,1,7,1,1,1,26,1,3,1,7,1,1,1,1,11,14,1,3,1,7,1,1,1,1,1,9,1,14,1,3,1,7,13,1,1,14,1,3,1,9,1,1,1,7,1,1,1,14,1,3,1,9,13,14,1,3,1,11,1,7,1,12,13,3,13,12,1,3,1,3,1,3,1,3,1,3,1,12,13,3,13,12,1,7,1,11,1,3,1,16,1,7,1,11,1,3,1,16,1,7,1,11,1,3,1,16,13,7,1,3,1,24,1,3,1,7,1,3,1,14,11,3,1,7,1,3,1,14,1,13,1,7,1,3,1,14,1,13,1,7,1,3,1,14,1,13,1,7,1,3,1,14,1,13,1,7,5,14,1,13,1,26,1,13,1,26,1,13,1,26,1,13,1,26,1,13,1,26,1,3,11,26,1,3,1,36,9,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,1,3,1,36,5,32

View file

@ -1,8 +1,10 @@
import collections import collections
import enum import enum
import itertools
import re
import sys import sys
import networkx import networkx
from typing import List, Iterable, Tuple, Optional, Set from typing import Dict, List, Tuple, Optional
# Halt indicates that the assembled program should terminate # Halt indicates that the assembled program should terminate
@ -189,9 +191,76 @@ def execute_program(memory: Memory, program_inputs: List[int], initial_instructi
# Problem specific code starts here # Problem specific code starts here
SCAFFOLD_CHAR = ord('#') SCAFFOLD_CHAR = ord('#')
ROBOT_CHAR = ord('^')
def build_graph_from_program(program_memory: Memory) -> networkx.Graph: class TurnDirection(enum.Enum):
LEFT = 'L'
RIGHT = 'R'
def __str__(self):
return self.value
class Direction(enum.IntEnum):
NORTH = 1
EAST = 2
SOUTH = 3
WEST = 4
# Given the direction we currently are, get the direction we need to turn to face this coordinate.
# Returns None if these are the same coordinate.
@staticmethod
def get_direction_to_coordinate(current_pos: Tuple[int, int], next_pos: Tuple[int, int]) -> Optional['Direction']:
current_row, current_col = current_pos
next_row, next_col = next_pos
direction_required = None
if next_col == current_col and next_row < current_row:
direction_required = Direction.NORTH
elif next_col == current_col and next_row > current_row:
direction_required = Direction.SOUTH
elif next_row == current_row and next_col < current_col:
direction_required = Direction.WEST
elif next_row == current_row and next_col > current_col:
direction_required = Direction.EAST
return direction_required
# Gets the direction we need to turn for fix.
# Returns None if we are currently facing the right direction
def get_turn_to_direction(self, new_direction: 'Direction') -> Optional[Tuple['TurnDirection', ...]]:
turn_distance = (self - new_direction) % 4
# if turn_distance == 2:
# breakpoint()
if turn_distance == 0:
return None
elif turn_distance == 3:
return (TurnDirection.RIGHT,)
else:
return (TurnDirection.LEFT,) * turn_distance
def move_coords_in_direction(self, pos: Tuple[int, int]) -> Tuple[int, int]:
D_ROWS = {
Direction.NORTH: -1,
Direction.SOUTH: 1,
Direction.EAST: 0,
Direction.WEST: 0
}
D_COLS = {
Direction.NORTH: 0,
Direction.SOUTH: 0,
Direction.EAST: 1,
Direction.WEST: -1
}
return (pos[0] + D_ROWS[self], pos[1] + D_COLS[self])
# Return a graph of all of the scaffolding, with a tuple represeting the robot's starting position
def build_graph_from_program(initial_memory_state: Memory) -> (networkx.Graph, Tuple[int, int]):
program_memory = initial_memory_state.copy()
# Add all edges that are directly above/below or directly left/right of our cursor # Add all edges that are directly above/below or directly left/right of our cursor
def add_adjacent_edges(scaffold_graph: networkx.Graph, row_cursor: int, col_cursor: int): def add_adjacent_edges(scaffold_graph: networkx.Graph, row_cursor: int, col_cursor: int):
scaffold_graph.add_node((row_cursor, col_cursor)) scaffold_graph.add_node((row_cursor, col_cursor))
@ -207,6 +276,7 @@ def build_graph_from_program(program_memory: Memory) -> networkx.Graph:
scaffold_graph = networkx.Graph() scaffold_graph = networkx.Graph()
row_cursor = 0 row_cursor = 0
col_cursor = 0 col_cursor = 0
robot_pos = None
for item in outputs: for item in outputs:
if item == ord('\n'): if item == ord('\n'):
row_cursor += 1 row_cursor += 1
@ -214,18 +284,206 @@ def build_graph_from_program(program_memory: Memory) -> networkx.Graph:
continue continue
elif item == SCAFFOLD_CHAR: elif item == SCAFFOLD_CHAR:
add_adjacent_edges(scaffold_graph, row_cursor, col_cursor) add_adjacent_edges(scaffold_graph, row_cursor, col_cursor)
elif item == ROBOT_CHAR:
add_adjacent_edges(scaffold_graph, row_cursor, col_cursor)
robot_pos = (row_cursor, col_cursor)
col_cursor += 1 col_cursor += 1
return scaffold_graph return scaffold_graph, robot_pos
def part1(initial_program_memory: Memory) -> int: def make_greedy_path(scaffold_graph: networkx.Graph, start_pos: Tuple[int, int]) -> str:
scaffold_graph = build_graph_from_program(initial_program_memory) path_components = []
forward_count = 0
robot_direction = Direction.NORTH
visited = set()
node_cursor = start_pos
while visited != set(scaffold_graph.nodes):
next_pos = robot_direction.move_coords_in_direction(node_cursor)
if next_pos not in scaffold_graph:
possible_points = set(scaffold_graph.neighbors(node_cursor)) - set(visited)
next_pos = sorted(possible_points, key=lambda x: (x[0], x[1]))[0]
new_direction = Direction.get_direction_to_coordinate(node_cursor, next_pos)
turns_needed = robot_direction.get_turn_to_direction(new_direction)
robot_direction = new_direction
if forward_count > 0:
path_components.append(str(forward_count))
path_components += [str(turn) for turn in turns_needed]
forward_count = 0
visited.add(node_cursor)
visited.add(next_pos)
node_cursor = next_pos
forward_count += 1
if forward_count > 0:
path_components.append(str(forward_count))
return ','.join(path_components)
# Find a component of the string that occurs more than once, starting at the given position and checking forwards/backwards
# based on the given offset
def find_component(path: str, start: int, offset: int) -> str:
component = path[start:offset] if offset > 0 else path[start + offset:]
if (offset > 0 and component[-1] != ',') or (offset < 0 and component[0] != ','):
return None
elif path.count(component) == 1:
return None
return component.strip(',')
# Get all substrings of s without the given component
def get_substrings_without_str(s: str, component: str) -> str:
locations = [(match.start(), match.end()) for match in re.finditer(re.escape(component), s)]
locations.insert(0, (None, None))
locations.append((None, None))
substrings = [s[location1[1]:location2[0]].strip(',') for location1, location2 in zip(locations, locations[1:])]
return [substring for substring in substrings if len(substring) > 0]
# If a path string is a duplicate itself, strip it down to its base component
def dedup_path_string(s: str) -> str:
normalized_s = s
# Need to join the two components with a comma so that we actually can spot the repetition (the string may not have a trailing comma)
if s[-1] != ',':
normalized_s = s + ','
# Find if the string is only composed of a portion of itself
repeat_index = (normalized_s + normalized_s).find(normalized_s, 1, -1)
if repeat_index == -1:
return s
else:
return s[:repeat_index].rstrip(',')
# Given the two other components, see if there's one final component left in the string
def get_last_component(path: str, component1: str, component2: str) -> Optional[str]:
path_without_component1 = get_substrings_without_str(path, component1)
# Get the path without component 1 or component 2
remaining_comonents = []
for substring in path_without_component1:
remaining_comonents += get_substrings_without_str(substring, component2)
# Make sure the last component we have is unique
if len(set(remaining_comonents)) > 1:
return None
last_component = dedup_path_string(remaining_comonents[0])
if len(last_component) > 20:
return None
return last_component
# Find the three compressible components of the path
# This is NOT pretty. This could be generalized by searching for all substrings, but that would be longer
def find_compressable_path_components(path: str) -> Tuple[str, str, str]:
MAX_LENGTH = 20
for i in range(MAX_LENGTH + 1):
path_candidate = path
# Find the first component at the start of the string
component1 = find_component(path_candidate, 0, i)
if component1 is None:
continue
# Remove it from both ends
path_candidate = path_candidate[len(component1):].lstrip(',')
if path_candidate.endswith(component1):
path_candidate = path_candidate[:-len(component1)].rstrip(',')
for j in range(MAX_LENGTH + 1):
trimmed_candidate = path_candidate
# We know there must be another unique component at the end of the string
component2 = find_component(trimmed_candidate, len(trimmed_candidate) - 1, -j)
if component2 is None:
continue
# Remove it from both ends
trimmed_candidate = trimmed_candidate[:-len(component2)].rstrip(',')
if trimmed_candidate.startswith(component2):
trimmed_candidate = trimmed_candidate[len(component2):].lstrip(',')
component3 = get_last_component(trimmed_candidate, component1, component2)
if component3 is None:
continue
return component1, component2, component3
else:
raise Exception("path is not compressible into three functions")
# Convert a path into a list of functions based on the given function defintiions
def make_function_nav_string(path: str, functions: Dict[str, str]) -> str:
i = 0
function_nav_string = []
while i < len(path):
for function_name, function in sorted(functions.items(), key=lambda x: len(x[1]), reverse=True):
if path[i:i+len(function)] == function:
function_nav_string.append(function_name)
# +1 for the comma
i += len(function) + 1
break
else:
raise ValueError('Functions not in path')
return ','.join(function_nav_string)
def part1(scaffold_graph: networkx.Graph) -> int:
return sum(row * col for row, col in scaffold_graph.nodes if scaffold_graph.degree((row, col)) > 2) return sum(row * col for row, col in scaffold_graph.nodes if scaffold_graph.degree((row, col)) > 2)
def part2(initial_memory_state: Memory, scaffold_graph: networkx.Graph, robot_pos: Tuple[int, int]):
def make_ascii_input(s: str) -> str:
return [ord(char) for char in s]
nav_string = make_greedy_path(scaffold_graph, robot_pos)
functions = find_compressable_path_components(nav_string)
named_functions = {name: function for name, function in zip(['A', 'B', 'C'], functions)}
function_nav_string = make_function_nav_string(nav_string, named_functions)
# Start the sequence of the interacitve mode
program_memory = initial_memory_state.copy()
program_memory[0] = 2
_, _, outputs = execute_program(program_memory, [
*make_ascii_input(function_nav_string + '\n'),
*make_ascii_input(named_functions['A'] + '\n'),
*make_ascii_input(named_functions['B'] + '\n'),
*make_ascii_input(named_functions['C'] + '\n'),
*make_ascii_input('n\n')
])
return outputs[-1]
# A debug method to print the entire graph
def print_scaffold_graph(scaffold_graph: networkx.Graph) -> None:
print(' ', end='')
max_row = max(node[0] for node in scaffold_graph.nodes) + 1
max_col = max(node[1] for node in scaffold_graph.nodes) + 1
for i in range(max_col):
print(i // 10 if i // 10 > 0 else ' ', end='')
print('')
print(' ', end='')
for i in range(max_col):
print(i % 10, end='')
print('')
for i in range(max_row):
print(f'{i:2} ', end='')
for j in range(max_col):
if (i, j) in scaffold_graph.nodes:
print('#', end='')
else:
print('.', end='')
print('')
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) != 2: if len(sys.argv) != 2:
# Today's part 2 produces a lot of output, so i wanted to keep them separate # Today's part 2 produces a lot of output, so i wanted to keep them separate
@ -237,4 +495,7 @@ if __name__ == "__main__":
for i, item in enumerate(f.read().rstrip().split(",")): for i, item in enumerate(f.read().rstrip().split(",")):
memory[i] = int(item) memory[i] = int(item)
print(part1(memory)) scaffold_graph, robot_pos = build_graph_from_program(memory)
print_scaffold_graph(scaffold_graph)
print(part1(scaffold_graph))
print(part2(memory, scaffold_graph, robot_pos))