From 4d5c4e86c6f53ad4f63e8c6f5c51006256a2de68 Mon Sep 17 00:00:00 2001 From: Sijmen Date: Wed, 3 Jan 2024 21:50:55 +0100 Subject: [PATCH] Add days 17 through 19 --- day17.py | 74 ++++++++++++++++++++++++++++++++++++++++++ day17b.py | 71 ++++++++++++++++++++++++++++++++++++++++ day18.py | 55 +++++++++++++++++++++++++++++++ day19.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 day17.py create mode 100644 day17b.py create mode 100644 day18.py create mode 100644 day19.py diff --git a/day17.py b/day17.py new file mode 100644 index 0000000..5a011dc --- /dev/null +++ b/day17.py @@ -0,0 +1,74 @@ +import heapq +from pprint import pprint +import sys +from typing import Any + + +DIRS = [(1, 0), (0, -1), (-1, 0), (0, 1)] + + +def main() -> None: + with open(sys.argv[1]) as f: + map = [[int(c) for c in l.strip()] for l in f] + + pprint(map) + + heap: list[tuple[int, tuple[int, int], int, int, tuple[Any, ...]]] = [(0, (0, 0), 0, 0, ())] + seen = set() + while heap: + (cost, (x, y), dir, straight, trace) = heapq.heappop(heap) + if (x, y, dir, straight) in seen: + continue + seen.add((x, y, dir, straight)) + + if straight >= 3: + continue + if (x, y) == (len(map) - 1, len(map[0]) - 1): + break + + (dx, dy) = DIRS[dir] + if (0 <= (y + dy) < len(map)) and (0 <= (x + dx) < len(map[y])): + newtrace = (*trace, (x + dx, y + dy, dir)) + newcost = cost + map[y + dy][x + dx] + heapq.heappush(heap, (newcost, (x + dx, y + dy), dir, straight + 1, newtrace)) + + newdir = (dir + 1) % 4 + (dx, dy) = DIRS[newdir] + if (0 <= (y + dy) < len(map)) and (0 <= (x + dx) < len(map[y])): + newtrace = (*trace, (x + dx, y + dy, newdir)) + newcost = cost + map[y + dy][x + dx] + heapq.heappush(heap, (newcost, (x + dx, y + dy), newdir, 0, newtrace)) + + newdir = (dir + 3) % 4 + (dx, dy) = DIRS[newdir] + if (0 <= (y + dy) < len(map)) and (0 <= (x + dx) < len(map[y])): + newtrace = (*trace, (x + dx, y + dy, newdir)) + newcost = cost + map[y + dy][x + dx] + heapq.heappush(heap, (newcost, (x + dx, y + dy), newdir, 0, newtrace)) + else: + print("oh no") + path = [["."] * len(map[y]) for y in range(len(map))] + for (x, y, dir) in trace: + path[y][x] = [">", "^", "<", "v"][dir] + print("\n".join("".join(line) for line in path)) + sys.exit(1) + + print() + + path = [["."] * len(map[y]) for y in range(len(map))] + for (x, y, dir) in trace: + path[y][x] = [">", "^", "<", "v"][dir] + print("\n".join("".join(line) for line in path)) + + cost = 0 + for (x, y, _) in trace: + cost += map[y][x] + print(cost) + +if __name__ == "__main__": + main() + + + + + diff --git a/day17b.py b/day17b.py new file mode 100644 index 0000000..e167f1f --- /dev/null +++ b/day17b.py @@ -0,0 +1,71 @@ +import heapq +from pprint import pprint +import sys +from typing import Any + + +DIRS = [(1, 0), (0, -1), (-1, 0), (0, 1)] + + +def main() -> None: + with open(sys.argv[1]) as f: + map = [[int(c) for c in l.strip()] for l in f] + + (w, h) = (len(map[0]), len(map)) + + heap: list[tuple[int, tuple[int, int], int, int, tuple[Any, ...]]] = [ + # cost, pos, dir, straight, trace + (0, (0, 0), 0, 0, ()), + (0, (0, 0), 3, 0, ()), + ] + seen = set() + it = 0 + while heap: + it += 1 + (cost, (x, y), dir, straight, trace) = heapq.heappop(heap) + if it >= 10000: + if (x, y, dir, straight) in seen: + continue + seen.add((x, y, dir, straight)) + + if (x, y) == (len(map[0]) - 1, len(map) - 1) and 10 >= straight > 3: + break + + (dx, dy) = DIRS[dir] + if 10 >= (straight + 1) and (0 <= (y + dy) < len(map)) and (0 <= (x + dx) < len(map[y])): + newtrace = trace + ((x + dx, y + dy, dir),) + newcost = cost + map[y + dy][x + dx] + heapq.heappush(heap, (newcost, (x + dx, y + dy), dir, straight + 1, newtrace)) + + if 11 >= (straight + 1) > 4: + newdir = (dir + 1) % 4 + (dx, dy) = DIRS[newdir] + if (0 <= (y + dy) < len(map)) and (0 <= (x + dx) < len(map[y])): + newtrace = trace + ((x + dx, y + dy, newdir),) + newcost = cost + map[y + dy][x + dx] + heapq.heappush(heap, (newcost, (x + dx, y + dy), newdir, 1, newtrace)) + + newdir = (dir + 3) % 4 + (dx, dy) = DIRS[newdir] + if (0 <= (y + dy) < len(map)) and (0 <= (x + dx) < len(map[y])): + newtrace = trace + ((x + dx, y + dy, newdir),) + newcost = cost + map[y + dy][x + dx] + heapq.heappush(heap, (newcost, (x + dx, y + dy), newdir, 1, newtrace)) + else: + print("oh no") + sys.exit(1) + + print() + + path = [[str(c) for c in row] for row in map] + for (x, y, dir) in trace: + # path[y][x] = "\033[93m" + [">", "^", "<", "v"][dir] + "\033[0m" + path[y][x] = f"\033[93m{path[y][x]}\033[0m" + print("\n".join("".join(line) for line in path)) + print(cost) + +if __name__ == "__main__": + main() + +# 1040 too low +# 1066 too high \ No newline at end of file diff --git a/day18.py b/day18.py new file mode 100644 index 0000000..7900b3b --- /dev/null +++ b/day18.py @@ -0,0 +1,55 @@ +import sys + +DIRS = { + "U": (0, -1), + "D": (0, 1), + "L": (-1, 0), + "R": (1, 0), + "3": (0, -1), + "1": (0, 1), + "2": (-1, 0), + "0": (1, 0), +} + + +def solve(lines: list[tuple[int, int]], points: int) -> int: + area = 0 + for i in range(len(lines)): + (x_a, y_a) = lines[i] + (x_b, y_b) = lines[(i + 1) % len(lines)] + area += (x_b + x_a) * (y_b - y_a) // 2 + + return area + points // 2 + 1 + + +def main() -> None: + (x1, x2, y1, y2) = (0, 0, 0, 0) + (lines1, lines2) = ([], []) + (points1, points2) = (0, 0) + + with open(sys.argv[1]) as f: + for line in f: + (dir, steps, color) = line.split() + + (dx1, dy1) = DIRS[dir] + steps1 = int(steps) + lines1.append((x1, y1)) + x1 += dx1 * steps1 + y1 += dy1 * steps1 + points1 += steps1 + + (dx2, dy2) = DIRS[color[7]] + steps2 = int(color[2:7], 16) + lines2.append((x2, y2)) + x2 += dx2 * steps2 + y2 += dy2 * steps2 + points2 += steps2 + + part1 = solve(lines1, points1) + part2 = solve(lines2, points2) + + print(part1, part2) + + +if __name__ == "__main__": + main() diff --git a/day19.py b/day19.py new file mode 100644 index 0000000..314a178 --- /dev/null +++ b/day19.py @@ -0,0 +1,97 @@ +from pprint import pprint +import sys + +def part1(workflows: dict[str, list[list[str]]], ratings: str) -> int: + result = 0 + + for rating in ratings.splitlines(): + assert [r.split("=")[0] for r in rating[1:-1].split(",")] == list("xmas") + (x, m, a, s) = (int(r.split("=")[1]) for r in rating[1:-1].split(",")) + + workflow = "in" + while workflow not in "RA": + print(workflow) + for rule in workflows[workflow]: + match rule: + case [target]: + workflow = target + break + case [condition, target]: + if eval(condition): + workflow = target + break + + if workflow == "A": + result += sum((x, m, a, s)) + + return result + + +def part2(workflows: dict[str, list[list[str]]]) -> int: + result = 0 + stack = [("in", (1, 4001), (1, 4001), (1, 4001), (1, 4001))] + while stack: + (workflow, x, m, a, s) = stack.pop() + + if workflow == "A": + print(x, m, a, s) + result += (x[1] - x[0]) * (m[1] - m[0]) * (a[1] - a[0]) * (s[1] - s[0]) + continue + + if workflow == "R": + continue + + for rule in workflows[workflow]: + match rule: + case [target]: + stack.append((target, x, m, a, s)) + case [condition, target] if ">" in condition: + (var, value_) = condition.split(">") + value = int(value_) + 1 + match var: + case "x": + stack.append((target, (value, x[1]), m, a, s)) + x = (x[0], value) + case "m": + stack.append((target, x, (value, m[1]), a, s)) + m = (m[0], value) + case "a": + stack.append((target, x, m, (value, a[1]), s)) + a = (a[0], value) + case "s": + stack.append((target, x, m, a, (value, s[1]))) + s = (s[0], value) + case [condition, target] if "<" in condition: + (var, value_) = condition.split("<") + value = int(value_) + match var: + case "x": + stack.append((target, (x[0], value), m, a, s)) + x = (value, x[1]) + case "m": + stack.append((target, x, (m[0], value), a, s)) + m = (value, m[1]) + case "a": + stack.append((target, x, m, (a[0], value), s)) + a = (value, a[1]) + case "s": + stack.append((target, x, m, a, (s[0], value))) + s = (value, s[1]) + return result + +def main() -> None: + with open(sys.argv[1]) as f: + (workflows_, ratings) = f.read().split("\n\n") + + workflows = {} + for workflow in workflows_.splitlines(): + (name, rules_) = workflow.split("{", 1) + rules = [rule.split(":") for rule in rules_[:-1].split(",")] + workflows[name] = rules + + p1 = part1(workflows, ratings) + p2 = part2(workflows) + print(p1, p2) + +if __name__ == "__main__": + main() \ No newline at end of file