From 2a26f9ffa7feb9703632c42e677d86d9da4ba17e Mon Sep 17 00:00:00 2001 From: Tyler Hoffman Date: Thu, 14 Dec 2023 07:03:54 -0500 Subject: [PATCH] Day 14 (#22) * Get parser working * Solve 14.a * Solve 14.b --- aoc_2023/day_14/__init__.py | 0 aoc_2023/day_14/a.py | 64 +++++++++++++++ aoc_2023/day_14/b.py | 142 +++++++++++++++++++++++++++++++++ aoc_2023/day_14/from_prompt.py | Bin 0 -> 202 bytes aoc_2023/day_14/input.txt | Bin 0 -> 10122 bytes aoc_2023/day_14/parser.py | 5 ++ tests/test_day_14/__init__.py | 0 tests/test_day_14/test_a.py | 10 +++ tests/test_day_14/test_b.py | 10 +++ 9 files changed, 231 insertions(+) create mode 100644 aoc_2023/day_14/__init__.py create mode 100644 aoc_2023/day_14/a.py create mode 100644 aoc_2023/day_14/b.py create mode 100644 aoc_2023/day_14/from_prompt.py create mode 100644 aoc_2023/day_14/input.txt create mode 100644 aoc_2023/day_14/parser.py create mode 100644 tests/test_day_14/__init__.py create mode 100644 tests/test_day_14/test_a.py create mode 100644 tests/test_day_14/test_b.py diff --git a/aoc_2023/day_14/__init__.py b/aoc_2023/day_14/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aoc_2023/day_14/a.py b/aoc_2023/day_14/a.py new file mode 100644 index 0000000..ae91d60 --- /dev/null +++ b/aoc_2023/day_14/a.py @@ -0,0 +1,64 @@ +from dataclasses import dataclass +from functools import cached_property +from aoc_2023.day_14.parser import Parser + + +@dataclass +class Day14PartASolver: + panel: list[list[str]] + + @property + def solution(self) -> int: + panel = self.tilt_north(self.panel) + return self.count_north_load(panel) + + def count_north_load(self, panel: list[list[str]]) -> int: + output = 0 + for x in range(self.width): + for y in range(self.height): + if panel[y][x] == "O": + output += self.height - y + return output + + def tilt_north(self, panel: list[list[str]]) -> list[list[str]]: + output = [["." for _ in range(self.width)] for _ in range(self.height)] + for x in range(self.width): + dest = 0 + for y in range(self.height): + match panel[y][x]: + case ".": + ... + case "#": + output[y][x] = "#" + dest = y + 1 + case "O": + output[dest][x] = "O" + dest += 1 + case _: + assert False + return output + + @cached_property + def width(self) -> int: + return len(self.panel[0]) + + @cached_property + def height(self) -> int: + return len(self.panel) + + +def solve(input: str) -> int: + data = Parser.parse(input) + solver = Day14PartASolver(data) + + return solver.solution + + +def get_solution() -> int: + with open("aoc_2023/day_14/input.txt", "r") as f: + input = f.read() + return solve(input) + + +if __name__ == "__main__": + print(get_solution()) diff --git a/aoc_2023/day_14/b.py b/aoc_2023/day_14/b.py new file mode 100644 index 0000000..5efe406 --- /dev/null +++ b/aoc_2023/day_14/b.py @@ -0,0 +1,142 @@ +from dataclasses import dataclass +from functools import cached_property +from aoc_2023.day_14.parser import Parser + + +@dataclass +class Day14PartBSolver: + panel: list[list[str]] + cycles: int = 1000000000 + + @property + def solution(self) -> int: + seen_at = dict[tuple[tuple[str, ...], ...], int]() + + panel = self.panel + for i in range(self.cycles): + panel = self.do_cycle(panel) + as_tuple = tuple([tuple([x for x in line]) for line in panel]) + if as_tuple in seen_at: + first_sighted = seen_at[as_tuple] + cycle_length = i - first_sighted + cycles_left = self.cycles - i - 1 + offset = cycles_left % cycle_length + index = first_sighted + offset + for p, j in seen_at.items(): + if j == index: + return self.count_north_load([[x for x in line] for line in p]) + else: + seen_at[as_tuple] = i + return self.count_north_load(panel) + + def do_cycle(self, panel: list[list[str]]) -> list[list[str]]: + panel = self.tilt_north(panel) + panel = self.tilt_west(panel) + panel = self.tilt_south(panel) + panel = self.tilt_east(panel) + return panel + + def count_north_load(self, panel: list[list[str]]) -> int: + output = 0 + for x in range(self.width): + for y in range(self.height): + if panel[y][x] == "O": + output += self.height - y + return output + + def tilt_north(self, panel: list[list[str]]) -> list[list[str]]: + output = [["." for _ in range(self.width)] for _ in range(self.height)] + for x in range(self.width): + dest = 0 + for y in range(self.height): + match panel[y][x]: + case ".": + ... + case "#": + output[y][x] = "#" + dest = y + 1 + case "O": + output[dest][x] = "O" + dest += 1 + case _: + assert False + return output + + def tilt_south(self, panel: list[list[str]]) -> list[list[str]]: + output = [["." for _ in range(self.width)] for _ in range(self.height)] + for x in range(self.width): + dest = self.height - 1 + for y in range(self.height - 1, -1, -1): + match panel[y][x]: + case ".": + ... + case "#": + output[y][x] = "#" + dest = y - 1 + case "O": + output[dest][x] = "O" + dest -= 1 + case _: + assert False + return output + + def tilt_west(self, panel: list[list[str]]) -> list[list[str]]: + output = [["." for _ in range(self.width)] for _ in range(self.height)] + for y in range(self.height): + dest = 0 + for x in range(self.width): + match panel[y][x]: + case ".": + ... + case "#": + output[y][x] = "#" + dest = x + 1 + case "O": + output[y][dest] = "O" + dest += 1 + case _: + assert False + return output + + def tilt_east(self, panel: list[list[str]]) -> list[list[str]]: + output = [["." for _ in range(self.width)] for _ in range(self.height)] + for y in range(self.height): + dest = self.width - 1 + for x in range(self.width - 1, -1, -1): + match panel[y][x]: + case ".": + ... + case "#": + output[y][x] = "#" + dest = x - 1 + case "O": + output[y][dest] = "O" + dest -= 1 + case _: + assert False + return output + + @cached_property + def width(self) -> int: + return len(self.panel[0]) + + @cached_property + def height(self) -> int: + return len(self.panel) + + +def solve(input: str) -> int: + data = Parser.parse(input) + solver = Day14PartBSolver(data) + + return solver.solution + + +def get_solution() -> int: + with open("aoc_2023/day_14/input.txt", "r") as f: + input = f.read() + return solve(input) + + +if __name__ == "__main__": + print(get_solution()) diff --git a/aoc_2023/day_14/from_prompt.py b/aoc_2023/day_14/from_prompt.py new file mode 100644 index 0000000000000000000000000000000000000000..aa32700633c19d31d41cbe79090fdeacf8cadac3 GIT binary patch literal 202 zcmV;*05$&rM@dveQdv+`0Fxu1*ELZ>W~d{{k^N6DVDPiw`?fEzqp-hq|Jzt1Fx3IfHOI%F2%i;w(ATI^mgoB*%+>lqzR85w)WQ< zIrl+j23hiXp9dkb0RT7et3)N@r9&9J4@RAg=ouvfBcv7*LQ5ye^!&}I71p@>Jp4;1 E|HxQgr2qf` literal 0 HcmV?d00001 diff --git a/aoc_2023/day_14/input.txt b/aoc_2023/day_14/input.txt new file mode 100644 index 0000000000000000000000000000000000000000..3646be886e8a498a993d29bc72d6c6138a126e30 GIT binary patch literal 10122 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 literal 0 HcmV?d00001 diff --git a/aoc_2023/day_14/parser.py b/aoc_2023/day_14/parser.py new file mode 100644 index 0000000..2b15c4f --- /dev/null +++ b/aoc_2023/day_14/parser.py @@ -0,0 +1,5 @@ +class Parser: + @staticmethod + def parse(input: str) -> list[list[str]]: + lines = input.strip().splitlines() + return [list(line) for line in lines] diff --git a/tests/test_day_14/__init__.py b/tests/test_day_14/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_day_14/test_a.py b/tests/test_day_14/test_a.py new file mode 100644 index 0000000..9ec5869 --- /dev/null +++ b/tests/test_day_14/test_a.py @@ -0,0 +1,10 @@ +from aoc_2023.day_14.a import get_solution, solve +from aoc_2023.day_14.from_prompt import SAMPLE_DATA, SAMPLE_SOLUTION_A + + +def test_solve(): + assert solve(SAMPLE_DATA) == SAMPLE_SOLUTION_A + + +def test_my_solution(): + assert get_solution() == 107053 diff --git a/tests/test_day_14/test_b.py b/tests/test_day_14/test_b.py new file mode 100644 index 0000000..5174285 --- /dev/null +++ b/tests/test_day_14/test_b.py @@ -0,0 +1,10 @@ +from aoc_2023.day_14.b import get_solution, solve +from aoc_2023.day_14.from_prompt import SAMPLE_DATA, SAMPLE_SOLUTION_B + + +def test_solve(): + assert solve(SAMPLE_DATA) == SAMPLE_SOLUTION_B + + +def test_my_solution(): + assert get_solution() == 88371