2023.18
This commit is contained in:
parent
21bc4c1c54
commit
ed5fda867f
7 changed files with 139 additions and 12 deletions
1
challenges/2023/18-lavaductLagoon/README.md
Normal file
1
challenges/2023/18-lavaductLagoon/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# [Day 18: Lavaduct Lagoon](https://adventofcode.com/2023/day/18)
|
88
challenges/2023/18-lavaductLagoon/main.py
Normal file
88
challenges/2023/18-lavaductLagoon/main.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
import sys
|
||||
import re
|
||||
from collections import namedtuple
|
||||
import gridutil.coord as cu
|
||||
import gridutil.grid as gu
|
||||
|
||||
|
||||
Instruction = namedtuple("Instruction", ["direction", "dist", "colour"])
|
||||
PARSE_RE = re.compile(r"([RDUL]) (\d+) \(#([a-f\d]{6})\)")
|
||||
DIRECTION_TRANSFORMATION = {
|
||||
"R": cu.Direction.Right,
|
||||
"L": cu.Direction.Left,
|
||||
"U": cu.Direction.Up,
|
||||
"D": cu.Direction.Down,
|
||||
"0": cu.Direction.Right,
|
||||
"1": cu.Direction.Down,
|
||||
"2": cu.Direction.Left,
|
||||
"3": cu.Direction.Up,
|
||||
}
|
||||
|
||||
|
||||
def parse(instr: str) -> list[Instruction]:
|
||||
res = []
|
||||
for line in instr.splitlines():
|
||||
m = PARSE_RE.match(line)
|
||||
assert m is not None
|
||||
|
||||
raw_dir, dist, colour = m.groups()
|
||||
parsed_dir = DIRECTION_TRANSFORMATION[raw_dir]
|
||||
assert parsed_dir is not None
|
||||
|
||||
res.append(Instruction(parsed_dir, int(dist), colour))
|
||||
return res
|
||||
|
||||
|
||||
def run(instructions: list[Instruction]) -> int:
|
||||
perimeter = 0
|
||||
vertices = [cu.Coordinate(0, 0)]
|
||||
for instruction in instructions:
|
||||
perimeter += instruction.dist
|
||||
vertices.append(
|
||||
cu.add(
|
||||
vertices[-1], cu.mult(instruction.direction.delta(), instruction.dist)
|
||||
)
|
||||
)
|
||||
|
||||
vertices = vertices[:-1]
|
||||
|
||||
area = cu.area(vertices)
|
||||
|
||||
# This is Pick's theorem.
|
||||
# Normally, we'd want to just get the internal area, which the Shoelace formula would do.
|
||||
# But since we want the area including walls that we assume are a single
|
||||
# unit thick, we apply Pick's theorem as this counts all coordinates that
|
||||
# the walls pass through, which in this case is effectively the same thing.
|
||||
return int(area + perimeter / 2) + 1
|
||||
|
||||
|
||||
def one(instr: str):
|
||||
instructions = parse(instr)
|
||||
return run(instructions)
|
||||
|
||||
|
||||
def two(instr: str):
|
||||
instructions = parse(instr)
|
||||
for i, instruction in enumerate(instructions):
|
||||
instructions[i] = Instruction(
|
||||
DIRECTION_TRANSFORMATION[instruction.colour[-1]],
|
||||
int(instruction.colour[:5], base=16),
|
||||
"",
|
||||
)
|
||||
return run(instructions)
|
||||
|
||||
|
||||
def _debug(*args, **kwargs):
|
||||
kwargs["file"] = sys.stderr
|
||||
print(*args, **kwargs)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]:
|
||||
print("Missing day argument", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
inp = sys.stdin.read().strip()
|
||||
if sys.argv[1] == "1":
|
||||
print(one(inp))
|
||||
else:
|
||||
print(two(inp))
|
18
challenges/2023/18-lavaductLagoon/tests.json
Normal file
18
challenges/2023/18-lavaductLagoon/tests.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"1": [
|
||||
{
|
||||
"is": "62",
|
||||
"input": "R 6 (#70c710)\nD 5 (#0dc571)\nL 2 (#5713f0)\nD 2 (#d2c081)\nR 2 (#59c680)\nD 2 (#411b91)\nL 5 (#8ceee2)\nU 2 (#caa173)\nL 1 (#1b58a2)\nU 2 (#caa171)\nR 2 (#7807d2)\nU 3 (#a77fa3)\nL 2 (#015232)\nU 2 (#7a21e3)\n\n"
|
||||
},
|
||||
{
|
||||
"is": "20",
|
||||
"input": "R 2 (#000000)\nD 1 (#000000)\nR 2 (#000000)\nU 1 (#000000)\nR 2 (#000000)\nD 2 (#000000)\nL 6 (#000000)\nU 2 (#000000)\n"
|
||||
}
|
||||
],
|
||||
"2": [
|
||||
{
|
||||
"is": "952408144115",
|
||||
"input": "R 6 (#70c710)\nD 5 (#0dc571)\nL 2 (#5713f0)\nD 2 (#d2c081)\nR 2 (#59c680)\nD 2 (#411b91)\nL 5 (#8ceee2)\nU 2 (#caa173)\nL 1 (#1b58a2)\nU 2 (#caa171)\nR 2 (#7807d2)\nU 3 (#a77fa3)\nL 2 (#015232)\nU 2 (#7a21e3)\n\n"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -30,4 +30,5 @@ A day denoted with a star means it has a visualisation.
|
|||
| 14* - Parabolic Reflector Dish | ★ ★ | Python | Why do I always overcomplicate cycle detection?! |
|
||||
| 15 - Lens Library | ★ ★ | Go | Still took some brainpower but this time the brainpower was needed to work out what the problem was, *not* to work out how to solve the problem. |
|
||||
| 16 - The Floor Will Be Lava | ★ ★ | Python | Pathfinding, sort of, but also brute forceable?? |
|
||||
| 17 - Clumsy Crucible | ★ ★ | Python | This taught me quite a lot about how to meddle with Djikstra's |
|
||||
| 17 - Clumsy Crucible | ★ ★ | Python | This taught me quite a lot about how to meddle with Djikstra's |
|
||||
| 18 - Ladaduct Lagoon | ★ ★ | Python | Nothing quite like a problem that I thought I knew the solution to showing up my lack of mathematical knowledge. |
|
|
@ -31,3 +31,5 @@
|
|||
{"day": 16, "part": 2, "runner": "py", "min": 2.7863943576812744, "max": 4.14529013633728, "avg": 3.1346225261688234, "n": 15}
|
||||
{"day": 17, "part": 1, "runner": "py", "min": 5.36311674118042, "max": 5.36311674118042, "avg": 5.36311674118042, "n": 1}
|
||||
{"day": 17, "part": 2, "runner": "py", "min": 26.201914072036743, "max": 26.201914072036743, "avg": 26.201914072036743, "n": 1}
|
||||
{"day": 18, "part": 1, "runner": "py", "min": 0.02330160140991211, "max": 0.03203868865966797, "avg": 0.024628419876098633, "n": 100}
|
||||
{"day": 18, "part": 2, "runner": "py", "min": 0.023529052734375, "max": 0.030207157135009766, "avg": 0.02483478546142578, "n": 100}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue