2 Commits

Author SHA1 Message Date
be2244eca9 Inline module
Because this is Terraform, and it's the ultimate optimisation technique
2024-12-20 20:15:30 +01:00
395463dc4a Implement 2024 day 20 2024-12-20 09:46:53 +01:00
5 changed files with 124 additions and 24 deletions

View File

@@ -2,17 +2,24 @@ variable "prev" {
type = map(number) type = map(number)
} }
module "transform" {
source = "../transform"
for_each = var.prev
num = each.key
}
locals { locals {
not_a_module = {
for num, _ in var.prev : num => (
tonumber(num) == 0
? [1]
: (
length(tostring(num)) % 2 == 0
? [
tonumber(substr(tostring(num), 0, length(tostring(num)) / 2)),
tonumber(substr(tostring(num), length(tostring(num)) / 2, length(tostring(num)) / 2)),
]
: [num * 2024]
)
)
}
by_value = flatten([ by_value = flatten([
for key, value in module.transform : for key, value in local.not_a_module :
[for result in value.result : { num = result, count = var.prev[key] }] [for result in value : { num = result, count = var.prev[key] }]
]) ])
grouped = { for kv in local.by_value : kv.num => kv.count... } grouped = { for kv in local.by_value : kv.num => kv.count... }

View File

@@ -1,15 +0,0 @@
variable "num" {
type = number
}
locals {
as_str = tostring(var.num)
len = length(local.as_str)
half = floor(length(local.as_str) / 2)
first = try(tonumber(substr(local.as_str, 0, local.half)), -1)
second = try(tonumber(substr(local.as_str, local.half, local.half)), -1)
}
output "result" {
value = var.num == 0 ? [1] : local.len % 2 == 0 ? [local.first, local.second] : [var.num * 2024]
}

View File

@@ -0,0 +1,82 @@
import itertools
import numpy
from . import SeparateRunner
DIRECTIONS = [
(-1, 0),
(1, 0),
(0, -1),
(0, 1),
]
CHEATS = [
(-2, 0),
(2, 0),
(0, -2),
(0, 2),
]
def parse_path(input: str) -> dict[tuple[int, int], int]:
grid = numpy.array(list(map(list, input.strip().split("\n"))))
ys, xs = numpy.nonzero(grid == "S")
sx, sy = int(xs[0]), int(ys[0])
nx, ny = sx, sy
path = {
(sx, sy): 0,
}
while grid[ny, nx] != "E":
x, y = nx, ny
for dx, dy in DIRECTIONS:
if grid[y + dy, x + dx] == "#" or (x + dx, y + dy) in path:
continue
nx = x + dx
ny = y + dy
break
path[nx, ny] = len(path)
return path
def get_savings(a: tuple[tuple[int, int], int], b: tuple[tuple[int, int], int]) -> int:
(ax, ay), ad = a
(bx, by), bd = b
dist = abs(bx - ax) + abs(by - ay)
if dist <= 20:
return bd - ad - dist
else:
return 0
class DayRunner(SeparateRunner):
@classmethod
def part1(cls, input: str, limit: int = 100) -> int:
path = parse_path(input)
total = 0
for (px, py), dist in path.items():
for dx, dy in CHEATS:
if (other := path.get((px + dx, py + dy))) is not None:
savings = dist - other - 2
if savings >= limit:
total += 1
return total
@classmethod
def part2(cls, input: str, limit: int = 100) -> int:
path = parse_path(input)
return sum(
get_savings(a, b) >= limit
for a, b in itertools.combinations(path.items(), 2)
)

15
2024/tests/samples/20.txt Normal file
View File

@@ -0,0 +1,15 @@
###############
#...#...#.....#
#.#.#.#.#.###.#
#S#...#.#.#...#
#######.#.#.###
#######.#.#...#
#######.#.###.#
###..E#...#...#
###.#######.###
#...###...#...#
#.#####.#.###.#
#.#...#.#.#...#
#.#.#.#.#.#.###
#...#...#...###
###############

11
2024/tests/test_day20.py Normal file
View File

@@ -0,0 +1,11 @@
from aoc.days.day20 import DayRunner
from . import get_data
def test_sample_part1() -> None:
assert DayRunner.part1(get_data(20), limit=1) == 44
def test_sample_part2() -> None:
assert DayRunner.part2(get_data(20), limit=50) == 285