Day 17 part 2

This commit is contained in:
Dece 2019-12-18 02:04:40 +01:00
parent 729dee98cb
commit a76864f407
3 changed files with 140 additions and 22 deletions

View file

@ -1,29 +1,89 @@
from collections import defaultdict
from grid import Grid from grid import Grid
from intcode import Intcode from intcode import Intcode
from vector import *
def main(): def main():
with open("day17.txt", "rt") as input_file: with open("day17.txt", "rt") as input_file:
codes = Intcode.parse_input(input_file.read().rstrip()) codes = Intcode.parse_input(input_file.read().rstrip())
camera = Camera(codes) # Part 1
camera.run() robot = Robot(codes)
intersections = camera.intersect() robot.run()
intersections = robot.intersect()
print("Sum:", sum(x * y for x, y in intersections)) print("Sum:", sum(x * y for x, y in intersections))
# Part 2
start = robot.start
sx, sy, so = start
print(f"Start at {(sx, sy)} oriented {so}.")
path = compute_path(robot.img, start)
print(f"Traced path: {path}.")
# Patterns found in my editor from the above result...
patterns = {
"M": "ABBACBCCBA",
"A": ['R', 10, 'R', 8, 'L', 10, 'L', 10],
"B": ['R', 8, 'L', 6, 'L', 6],
"C": ['L', 10, 'R', 10, 'L', 6],
}
codes[0] = 2
robot = Robot(codes, patterns=patterns, video_fb=False)
robot.run()
class Camera(Intcode):
def __init__(self, *args, **kwargs): N = ord("\n")
S = ord("#")
class Robot(Intcode):
ORI_U = (0, -1)
ORI_R = (1, 0)
ORI_D = (0, +1)
ORI_L = (-1, 0)
ORI_INDEXES = {ORI_U: 0, ORI_R: 1, ORI_D: 2, ORI_L: 3}
ASCII_ORI = {"^": ORI_U, ">": ORI_R, "v": ORI_D, "<": ORI_L}
def __init__(self, *args, patterns=None, video_fb=False, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.out_x = 0 self.out_x = 0
self.out_y = 0 self.out_y = 0
self.img = Grid() self.img = Grid()
self.start = None
self.moving = False
self.video_fb = video_fb
self.video_last_byte = None
self.patterns = patterns
self.robot_inputs = []
if self.patterns:
self.input_gen()
def input_data(self):
self.moving = True
data = self.robot_inputs.pop(0)
return data
def input_gen(self):
self.robot_inputs += [ord(x) for x in ",".join(self.patterns["M"])] + [N]
for pname in "ABC":
pdata = ",".join(map(lambda x: str(x), self.patterns[pname]))
self.robot_inputs += [ord(x) for x in pdata] + [N]
self.robot_inputs += [ord("y" if self.video_fb else "n"), N]
def output_data(self, data): def output_data(self, data):
if data == ord("\n"): if data > 256:
print("Output", data)
return
if self.video_fb:
print(chr(data), end="")
if all(d == N for d in [data, self.video_last_byte]):
input()
self.video_last_byte = data
if self.moving:
return
if data == N:
self.out_x, self.out_y = 0, self.out_y + 1 self.out_x, self.out_y = 0, self.out_y + 1
else: else:
self.img.g[self.out_y][self.out_x] = data self.img.g[self.out_y][self.out_x] = data
@ -32,19 +92,49 @@ class Camera(Intcode):
def intersect(self): def intersect(self):
intersections = [] intersections = []
g = self.img.g g = self.img.g
for x, col in list(g.items()).copy(): for y, row in list(g.items()).copy():
for y, v in list(col.items()).copy(): for x, v in list(row.items()).copy():
if all( if all(e == S for e in [v, g[y][x-1], g[y][x+1], g[y+1][x], g[y-1][x]]):
e == ord("#")
for e in [v, g[x][y-1], g[x][y+1], g[x+1][y], g[x-1][y]]
):
print("O", end="")
intersections.append((x, y)) intersections.append((x, y))
else: elif chr(v) in Robot.ASCII_ORI.keys():
print(chr(v), end="") self.start = (x, y, Robot.ASCII_ORI[chr(v)])
print()
return intersections return intersections
def compute_path(grid, start):
pos, o = (start[0], start[1]), start[2]
path = []
steps = 0
while True:
forward_pos = v2a(pos, o)
near_pos = grid.near_items(pos)
if near_pos[forward_pos] == S:
pos = forward_pos
steps += 1
continue
if steps:
path.append(steps)
steps = 0
for n in [p for p, v in near_pos.items() if v == S]:
res = turn(pos, n, o)
if res is not None:
path.append(res[0])
o = res[1]
break
else:
break
return path
def turn(pos, next_pos, cur_ori):
new_ori = (next_pos[0] - pos[0], next_pos[1] - pos[1])
diff = (Robot.ORI_INDEXES[new_ori] - Robot.ORI_INDEXES[cur_ori]) % 4
if diff == 1:
return "R", new_ori
elif diff == 3:
return "L", new_ori
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -6,7 +6,33 @@ class Grid:
def __init__(self): def __init__(self):
self.g = defaultdict(lambda: defaultdict(int)) self.g = defaultdict(lambda: defaultdict(int))
def values(self): @staticmethod
for a, chunk in self.g.items(): def near(p):
for b, v in chunk.items(): """Return a tuple of neighbor positions (up, left, down, right)."""
yield a, b, v return (
(p[0] , p[1] - 1),
(p[0] + 1, p[1] ),
(p[0] , p[1] + 1),
(p[0] - 1, p[1] ),
)
def near_items(self, p):
"""Return a dict of neighbor positions to values (U, L, D, R)."""
return {pos: self.g[pos[1]][pos[0]] for pos in Grid.near(p)}
def print_near(self, p):
print("".join([
chr(self.g[p[1] - 1][p[0] - 1]),
chr(self.g[p[1] - 1][p[0]]),
chr(self.g[p[1] - 1][p[0] + 1]),
]))
print("".join([
chr(self.g[p[1] ][p[0] - 1]),
chr(self.g[p[1] ][p[0]]),
chr(self.g[p[1] ][p[0] + 1]),
]))
print("".join([
chr(self.g[p[1] + 1][p[0] - 1]),
chr(self.g[p[1] + 1][p[0]]),
chr(self.g[p[1] + 1][p[0] + 1]),
]))

2
2019/vector.py Normal file
View file

@ -0,0 +1,2 @@
def v2a(a, b):
return a[0] + b[0], a[1] + b[1]