From b681e5cdb7959bfde32c563d93693c205af717bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Engl=C3=B6f=20Ytterstr=C3=B6m?= Date: Mon, 11 Dec 2023 00:19:34 +0100 Subject: [PATCH] Solve 2023:10 "Pipe Maze" Got completely stuck on part 2. Tried some polygon area calculations, but none provided the correct answer, most likely due to the unorthodox polygon points. I also tried _shoelace method_ without any luck. Had not heard about that one earlier, it was a good learning experience even though I vould not use it here. By the subreddit, several people had had luck using the ray method. > Part 2 using one of my favorite facts from > graphics engineering: lets say you have an > enclosed shape, and you want to color every > pixel inside of it. How do you know if a given > pixel is inside the shape or not? Well, it > turns out: if you shoot a ray in any direction > from the pixel and it crosses the boundary an > _odd number_ of times, it's _inside_. if it crosses > an even number of times, it's outside. Works > for all enclosed shapes, even self-intersecting > and non-convex ones. --- 2023-python/output/day_10.py | 103 ++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 26 deletions(-) diff --git a/2023-python/output/day_10.py b/2023-python/output/day_10.py index bb0c237..db34b6c 100644 --- a/2023-python/output/day_10.py +++ b/2023-python/output/day_10.py @@ -1,44 +1,95 @@ +import re +from collections import Counter, defaultdict, deque from output import answer n = 10 -title = "dddd" +title = "Pipe Maze" + + +D = (-1, 0), (0, 1), (1, 0), (0, -1) + +C = { + (-1, 0): ["|", "7", "F"], + (0, 1): ["-", "7", "J"], + (1, 0): ["|", "L", "J"], + (0, -1): ["-", "L", "F"], +} + +A = { + "S": [0, 1, 2, 3], + "-": [1, 3], + "|": [0, 2], + "F": [1, 2], + "L": [0, 1], + "7": [2, 3], + "J": [0, 3], +} @answer(1, "Answer is {}") -def part_1(data): - return data +def part_1(presolved): + return presolved[0] @answer(2, "Actually, answer is {}") -def part_2(data): - return data +def part_2(presolved): + return presolved[1] -# uncomment to solve parts in one go -# def presolve(data): -# return data +def presolve(data): + matrix = data.split() + w = len(matrix[0]) + h = len(matrix) + q = deque() + visited = set() + + for r in range(h): + if "S" in matrix[r]: + start = (r, matrix[r].index("S")) + q.append(start) + break + + while q: + o = q.popleft() + visited.add(o) + for di in A[matrix[o[0]][o[1]]]: + d = D[di] + r = o[0] + d[0] + c = o[1] + d[1] + if r >= 0 and r < h and c >= 0 and c < w: + t = matrix[r][c] + p = (r, c) + if p not in visited and t != "." and t in C[d]: + q.append(p) + p1 = len(visited) // 2 + + p2 = 0 + for y in range(h): + for x in range(w): + if (y, x) in visited: + continue + crosses = 0 + y2, x2 = y, x + while y2 < h and x2 < w: + c2 = matrix[y2][x2] + if (y2, x2) in visited and c2 not in "L7": + crosses += 1 + x2 += 1 + y2 += 1 + if crosses % 2 == 1: + p2 += 1 + + return p1, p2 if __name__ == "__main__": - # use dummy data - inp = """ - replace me - """.strip() + with open(f"./input/10.txt", "r") as f: + inp = f.read() - # uncomment to instead use stdin - # import sys; inp = sys.stdin.read().strip() - - # uncomment to use AoC provided puzzle input - # with open(f"./input/10.txt", "r") as f: - # inp = f.read() - - # uncomment to do initial data processing shared by part 1-2 - # inp = presolve(inp) + inp = presolve(inp) a = part_1(inp) - # b = part_2(inp) + b = part_2(inp) - # uncomment and replace 0 with actual output to refactor code - # and ensure nonbreaking changes - # assert a == 0 - # assert b == 0 + assert a == 6846 + assert b == 325