day09 finished
This commit is contained in:
parent
a60707185f
commit
3629b81bcf
7 changed files with 2150 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ I use python 3.11 without any libraries beyond the standard.
|
|||
|
||||
| Day | Time | Rank | Score | Time | Rank | Score |
|
||||
| --- | --------- | ----- | ----- | -------- | ----- | ----- |
|
||||
| 9 | 00:54:18 | 7719 | 0 | 01:07:37 | 4901 | 0 |
|
||||
| 8 | 00:41:51 | 7831 | 0 | 00:59:27 | 6325 | 0 |
|
||||
| 7 | 00:34:59 | 2683 | 0 | 00:45:45 | 2943 | 0 |
|
||||
| 6 | 00:14:52 | 9153 | 0 | 00:17:06 | 8413 | 0 |
|
||||
|
|
|
|||
0
advent/days/day09/__init__.py
Normal file
0
advent/days/day09/__init__.py
Normal file
2000
advent/days/day09/data/input.txt
Normal file
2000
advent/days/day09/data/input.txt
Normal file
File diff suppressed because it is too large
Load diff
8
advent/days/day09/data/test01.txt
Normal file
8
advent/days/day09/data/test01.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
R 4
|
||||
U 4
|
||||
L 3
|
||||
D 1
|
||||
R 4
|
||||
D 1
|
||||
L 5
|
||||
R 2
|
||||
8
advent/days/day09/data/test02.txt
Normal file
8
advent/days/day09/data/test02.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
R 5
|
||||
U 8
|
||||
L 8
|
||||
D 3
|
||||
R 17
|
||||
D 10
|
||||
L 25
|
||||
U 20
|
||||
92
advent/days/day09/solution.py
Normal file
92
advent/days/day09/solution.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
|
||||
from typing import Iterator
|
||||
|
||||
day_num = 9
|
||||
|
||||
|
||||
def part1(lines: Iterator[str]) -> int:
|
||||
lst = [Command.parse(line) for line in lines]
|
||||
return Command.walk(lst, 2)
|
||||
|
||||
|
||||
def part2(lines: Iterator[str]) -> int:
|
||||
lst = [Command.parse(line) for line in lines]
|
||||
return Command.walk(lst, 10)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Point:
|
||||
x: int
|
||||
y: int
|
||||
|
||||
@staticmethod
|
||||
def parse_direction(char: str) -> Point:
|
||||
""" Parses the given direction to a Point. May raise if invalid """
|
||||
match char:
|
||||
case 'R':
|
||||
return Point(1, 0)
|
||||
case 'U':
|
||||
return Point(0, 1)
|
||||
case 'L':
|
||||
return Point(-1, 0)
|
||||
case 'D':
|
||||
return Point(0, -1)
|
||||
case _:
|
||||
raise Exception(f"Unkown Direction: {char}")
|
||||
|
||||
def add(self, other: Point) -> Point:
|
||||
return Point(self.x + other.x, self.y + other.y)
|
||||
|
||||
def sub(self, other: Point) -> Point:
|
||||
return Point(self.x - other.x, self.y - other.y)
|
||||
|
||||
def is_unit(self) -> bool:
|
||||
""" return true, if this discribes any point (diagonally) adjacent to the origin"""
|
||||
return abs(self.x) <= 1 and abs(self.y) <= 1
|
||||
|
||||
def as_unit(self) -> Point:
|
||||
""" Compresses this Point to a point with unit components """
|
||||
def unit(num: int) -> int:
|
||||
return 0 if num == 0 else num // abs(num)
|
||||
return Point(unit(self.x), unit(self.y))
|
||||
|
||||
def step_to(self, other: Point) -> Point | None:
|
||||
diff = other.sub(self)
|
||||
if diff.is_unit():
|
||||
return None
|
||||
return self.add(diff.as_unit())
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Command:
|
||||
dir: Point
|
||||
steps: int
|
||||
|
||||
@staticmethod
|
||||
def parse(line: str) -> Command:
|
||||
""" Parse a command line. My raise exception if the was an illegal line"""
|
||||
match line.split():
|
||||
case [dir, steps]:
|
||||
return Command(Point.parse_direction(dir), int(steps))
|
||||
case _:
|
||||
raise Exception(f"Illegal line: {line}")
|
||||
|
||||
@staticmethod
|
||||
def walk(lst: list[Command], rope_length: int):
|
||||
""" Walks the whole rope in Planck length steps """
|
||||
rope = [Point(0, 0)] * rope_length
|
||||
visited = {rope[-1]}
|
||||
for command in lst:
|
||||
for _ in range(command.steps):
|
||||
rope[0] = rope[0].add(command.dir)
|
||||
for n in range(1, rope_length):
|
||||
moved_piece = rope[n].step_to(rope[n - 1])
|
||||
if not moved_piece:
|
||||
break
|
||||
rope[n] = moved_piece
|
||||
if n == rope_length - 1:
|
||||
visited.add(rope[n])
|
||||
|
||||
return len(visited)
|
||||
41
advent/days/day09/test_solution.py
Normal file
41
advent/days/day09/test_solution.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
from advent.common import utils
|
||||
|
||||
from .solution import Command, day_num, part1, part2
|
||||
|
||||
|
||||
def test_part1():
|
||||
data = utils.read_data(day_num, 'test01.txt')
|
||||
expected = 13
|
||||
result = part1(data)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_part2():
|
||||
data = utils.read_data(day_num, 'test02.txt')
|
||||
expected = 36
|
||||
result = part2(data)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_short():
|
||||
data = utils.read_data(day_num, 'test01.txt')
|
||||
expected = 13
|
||||
lst = [Command.parse(line) for line in data]
|
||||
result = Command.walk(lst, 2)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_long1():
|
||||
data = utils.read_data(day_num, 'test01.txt')
|
||||
expected = 1
|
||||
lst = [Command.parse(line) for line in data]
|
||||
result = Command.walk(lst, 10)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_long2():
|
||||
data = utils.read_data(day_num, 'test02.txt')
|
||||
expected = 36
|
||||
lst = [Command.parse(line) for line in data]
|
||||
result = Command.walk(lst, 10)
|
||||
assert result == expected
|
||||
Loading…
Add table
Add a link
Reference in a new issue