-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Boilerplate * Solve 15.a * Solve 15.b * Factor out code and fix a testing woopsie
- Loading branch information
1 parent
e48ee3c
commit 42a9be3
Showing
11 changed files
with
177 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from dataclasses import dataclass | ||
from aoc_2023.day_15.common import hash_it | ||
from aoc_2023.day_15.parser import Parser | ||
|
||
|
||
@dataclass | ||
class Day15PartASolver: | ||
lines: list[str] | ||
|
||
@property | ||
def solution(self) -> int: | ||
return sum(hash_it(line) for line in self.lines) | ||
|
||
|
||
def solve(input: str) -> int: | ||
data = Parser.parse(input) | ||
solver = Day15PartASolver(data) | ||
|
||
return solver.solution | ||
|
||
|
||
def get_solution() -> int: | ||
with open("aoc_2023/day_15/input.txt", "r") as f: | ||
input = f.read() | ||
return solve(input) | ||
|
||
|
||
if __name__ == "__main__": | ||
print(get_solution()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
from dataclasses import dataclass, field | ||
from functools import cached_property | ||
from typing import Optional | ||
from aoc_2023.day_15.common import hash_it | ||
from aoc_2023.day_15.parser import Parser | ||
|
||
|
||
@dataclass | ||
class Minus: | ||
label: str | ||
|
||
|
||
@dataclass | ||
class Equal: | ||
label: str | ||
val: int | ||
|
||
|
||
@dataclass | ||
class Lens: | ||
label: str | ||
focus_length: int | ||
deleted: bool = False | ||
|
||
|
||
@dataclass(frozen=True) | ||
class Box: | ||
id: int | ||
lenses: list[Optional[Lens]] = field(hash=False, default_factory=list) | ||
lens_index_lookup: dict[str, Lens] = field(hash=False, default_factory=dict) | ||
|
||
@property | ||
def focusing_power(self) -> int: | ||
output = 0 | ||
box_num = self.id + 1 | ||
lenses = [lens for lens in self.lenses if lens and not lens.deleted] | ||
for i, lens in enumerate(lenses): | ||
lens_num = i + 1 | ||
output += box_num * lens_num * lens.focus_length | ||
|
||
return output | ||
|
||
def remove_lens(self, label: str) -> None: | ||
if label in self.lens_index_lookup: | ||
self.lens_index_lookup[label].deleted = True | ||
del self.lens_index_lookup[label] | ||
|
||
def set_lens(self, label: str, value) -> None: | ||
if label in self.lens_index_lookup: | ||
lens = self.lens_index_lookup[label] | ||
lens.focus_length = value | ||
else: | ||
lens = Lens(label, value) | ||
self.lenses.append(lens) | ||
self.lens_index_lookup[label] = lens | ||
|
||
|
||
@dataclass | ||
class Day15PartBSolver: | ||
lines: list[str] | ||
|
||
@property | ||
def solution(self) -> int: | ||
for op in self.operations: | ||
self.do_operation(op) | ||
return sum(box.focusing_power for box in self.boxes) | ||
|
||
@cached_property | ||
def boxes(self) -> list[Box]: | ||
return [Box(i, []) for i in range(256)] | ||
|
||
@cached_property | ||
def operations(self) -> list[Minus | Equal]: | ||
output = list[Minus | Equal]() | ||
for line in self.lines: | ||
if line[-1] == "-": | ||
output.append(Minus(line[:-1])) | ||
else: | ||
label, val = line.split("=") | ||
output.append(Equal(label, int(val))) | ||
return output | ||
|
||
def do_operation(self, op: Minus | Equal) -> None: | ||
box_id = hash_it(op.label) | ||
box = self.boxes[box_id] | ||
|
||
match op: | ||
case Minus(label): | ||
box.remove_lens(label) | ||
case Equal(label, val): | ||
box.set_lens(label, val) | ||
|
||
|
||
def solve(input: str) -> int: | ||
data = Parser.parse(input) | ||
solver = Day15PartBSolver(data) | ||
|
||
return solver.solution | ||
|
||
|
||
def get_solution() -> int: | ||
with open("aoc_2023/day_15/input.txt", "r") as f: | ||
input = f.read() | ||
return solve(input) | ||
|
||
|
||
if __name__ == "__main__": | ||
print(get_solution()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
def hash_it(line: str) -> int: | ||
output = 0 | ||
for char in line: | ||
output += ord(char) | ||
output *= 17 | ||
output %= 256 | ||
return output |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class Parser: | ||
@staticmethod | ||
def parse(input: str) -> list[str]: | ||
return input.strip().split(",") |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from aoc_2023.day_15.a import get_solution, solve | ||
from aoc_2023.day_15.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() == 517015 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from aoc_2023.day_15.b import get_solution, solve | ||
from aoc_2023.day_15.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() == 286104 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from aoc_2023.day_15.common import hash_it | ||
from aoc_2023.day_15.from_prompt import HASH, HASH_HASHED | ||
|
||
|
||
def test_hash(): | ||
assert hash_it(HASH) == HASH_HASHED |