Skip to content

Commit

Permalink
AoC 2023 Day 18 Part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
pareronia committed Dec 18, 2023
1 parent 17d8bc8 commit 8a2747d
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<!-- @BEGIN:ImplementationsTable:2023@ -->
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| python3 | [](src/main/python/AoC2023_01.py) | [](src/main/python/AoC2023_02.py) | [](src/main/python/AoC2023_03.py) | [](src/main/python/AoC2023_04.py) | [](src/main/python/AoC2023_05.py) | [](src/main/python/AoC2023_06.py) | [](src/main/python/AoC2023_07.py) | [](src/main/python/AoC2023_08.py) | [](src/main/python/AoC2023_09.py) | [](src/main/python/AoC2023_10.py) | [](src/main/python/AoC2023_11.py) | [](src/main/python/AoC2023_12.py) | [](src/main/python/AoC2023_13.py) | [](src/main/python/AoC2023_14.py) | [](src/main/python/AoC2023_15.py) | [](src/main/python/AoC2023_16.py) | [](src/main/python/AoC2023_17.py) | | | | | | | | |
| python3 | [](src/main/python/AoC2023_01.py) | [](src/main/python/AoC2023_02.py) | [](src/main/python/AoC2023_03.py) | [](src/main/python/AoC2023_04.py) | [](src/main/python/AoC2023_05.py) | [](src/main/python/AoC2023_06.py) | [](src/main/python/AoC2023_07.py) | [](src/main/python/AoC2023_08.py) | [](src/main/python/AoC2023_09.py) | [](src/main/python/AoC2023_10.py) | [](src/main/python/AoC2023_11.py) | [](src/main/python/AoC2023_12.py) | [](src/main/python/AoC2023_13.py) | [](src/main/python/AoC2023_14.py) | [](src/main/python/AoC2023_15.py) | [](src/main/python/AoC2023_16.py) | [](src/main/python/AoC2023_17.py) | [](src/main/python/AoC2023_18.py) | | | | | | | |
| java | [](src/main/java/AoC2023_01.java) | [](src/main/java/AoC2023_02.java) | [](src/main/java/AoC2023_03.java) | [](src/main/java/AoC2023_04.java) | [](src/main/java/AoC2023_05.java) | [](src/main/java/AoC2023_06.java) | [](src/main/java/AoC2023_07.java) | [](src/main/java/AoC2023_08.java) | [](src/main/java/AoC2023_09.java) | [](src/main/java/AoC2023_10.java) | [](src/main/java/AoC2023_11.java) | [](src/main/java/AoC2023_12.java) | [](src/main/java/AoC2023_13.java) | [](src/main/java/AoC2023_14.java) | [](src/main/java/AoC2023_15.java) | [](src/main/java/AoC2023_16.java) | [](src/main/java/AoC2023_17.java) | | | | | | | | |
| rust | [](src/main/rust/AoC2023_01/src/main.rs) | [](src/main/rust/AoC2023_02/src/main.rs) | [](src/main/rust/AoC2023_03/src/main.rs) | [](src/main/rust/AoC2023_04/src/main.rs) | | [](src/main/rust/AoC2023_06/src/main.rs) | [](src/main/rust/AoC2023_07/src/main.rs) | [](src/main/rust/AoC2023_08/src/main.rs) | [](src/main/rust/AoC2023_09/src/main.rs) | | | | | | [](src/main/rust/AoC2023_15/src/main.rs) | [](src/main/rust/AoC2023_16/src/main.rs) | [](src/main/rust/AoC2023_17/src/main.rs) | | | | | | | | |
<!-- @END:ImplementationsTable:2023@ -->
Expand Down
117 changes: 79 additions & 38 deletions src/main/python/AoC2023_18.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@
#

import sys
from typing import NamedTuple, Iterator
from typing import NamedTuple

from aoc.common import InputData
from aoc.common import SolutionBase
from aoc.common import aoc_samples
from aoc.common import log
from aoc.geometry import Direction
from aoc.geometry import Draw
from aoc.geometry import Position
from aoc.graph import flood_fill
from aoc.navigation import Heading
from aoc.navigation import NavigationWithHeading


class DigInstruction(NamedTuple):
direction: Direction
amount: int
big_direction: Direction
big_amount: int


Input = list[DigInstruction]
Expand All @@ -46,49 +43,93 @@ class DigInstruction(NamedTuple):
"""


class Polygon(NamedTuple):
vertices: list[Position]

def shoelace(self) -> int:
ans = 0
size = len(self.vertices)
for i in range(size):
ans += self.vertices[i].x * (
self.vertices[(i + 1) % size].y - self.vertices[i - 1].y
)
return abs(ans) // 2

def circumference(self) -> int:
ans = 0
for i in range(1, len(self.vertices)):
ans += self.vertices[i].manhattan_distance(self.vertices[i - 1])
return ans

def picks(self) -> int:
a = self.shoelace()
b = self.circumference()
return a - b // 2 + 1

def area(self) -> int:
return self.picks() + self.circumference()


class Solution(SolutionBase[Input, Output1, Output2]):
def parse_input(self, input_data: InputData) -> Input:
ans = []
for line in input_data:
d, a, _ = line.split()
ans.append(DigInstruction(Direction.from_str(d), int(a)))
d, a, hx = line.split()
bd = [
Direction.RIGHT,
Direction.DOWN,
Direction.LEFT,
Direction.UP,
][int(hx[7])]
ba = int(hx[2:7], 16)
ans.append(
DigInstruction(
Direction.from_str(d),
int(a),
bd,
ba,
)
)
return ans

def to_positions(
self, instructions: list[DigInstruction]
) -> list[Position]:
pos = Position(0, 0)
ans = [pos]
for instruction in instructions:
pos = pos.translate(
instruction.direction.vector, instruction.amount
)
ans.append(pos)
return ans

def to_positions_big(
self, instructions: list[DigInstruction]
) -> list[Position]:
pos = Position(0, 0)
ans = [pos]
for instruction in instructions:
pos = pos.translate(
instruction.big_direction.vector, instruction.big_amount
)
ans.append(pos)
return ans

def part_1(self, instructions: Input) -> Output1:
log(instructions)
nav = NavigationWithHeading(Position(0, 0), Heading.NORTH)
for ins in instructions:
for i in range(ins.amount):
nav.drift(Heading.from_direction(ins.direction), 1)
positions = {_ for _ in nav.get_visited_positions(True)}
for line in Draw.draw(positions, "#", "."):
log(line)
min_x = min(p.x for p in positions)
max_y = max(p.y for p in positions)
pos = Position(min_x - 1, max_y + 1)
while True:
pos = Position(pos.x + 1, pos.y - 1)
if pos in positions:
break
start = Position(pos.x + 1, pos.y - 1)
log(start)

def adjacent(pos: Position) -> Iterator[Position]:
for d in Direction.octants():
n = pos.translate(d.vector)
if n not in positions:
yield n

inside = flood_fill(start, adjacent)
return len(inside) + len(positions)

def part_2(self, input: Input) -> Output2:
return 0
positions = self.to_positions(instructions)
polygon = Polygon(positions)
return polygon.area()

def part_2(self, instructions: Input) -> Output2:
positions = self.to_positions_big(instructions)
polygon = Polygon(positions)
return polygon.area()

@aoc_samples(
(
("part_1", TEST, 62),
# ("part_2", TEST, "TODO"),
("part_2", TEST, 952408144115),
)
)
def samples(self) -> None:
Expand Down

0 comments on commit 8a2747d

Please sign in to comment.