Skip to content

Commit

Permalink
Day 18
Browse files Browse the repository at this point in the history
  • Loading branch information
drewolson committed Dec 18, 2024
1 parent 351d3b7 commit 64d63f2
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/aoc/runner/year2024.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import aoc/year2024/day14
import aoc/year2024/day15
import aoc/year2024/day16
import aoc/year2024/day17
import aoc/year2024/day18
import gleam/string

pub fn run(input: String, day: Int, part: Int) {
Expand Down Expand Up @@ -53,6 +54,8 @@ pub fn run(input: String, day: Int, part: Int) {
16, 2 -> input |> day16.part2 |> string.inspect
17, 1 -> input |> day17.part1
17, 2 -> input |> day17.part2 |> string.inspect
18, 1 -> input |> day18.part1(70, 1024) |> string.inspect
18, 2 -> input |> day18.part2(70)
_, _ ->
"Unknown day and part for 2024: day "
<> string.inspect(day)
Expand Down
120 changes: 120 additions & 0 deletions src/aoc/year2024/day18.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import aoc/util/parser.{type Parser}
import gleam/dict.{type Dict}
import gleam/int
import gleam/list
import gleam/order.{type Order}
import gleam/result
import gleam/set.{type Set}
import gleam/yielder.{type Yielder}
import gleamy/priority_queue.{type Queue} as pq
import party

type Coord =
#(Int, Int)

type Grid =
Dict(Coord, String)

type Node =
#(Int, Coord)

fn order(a: Node, b: Node) -> Order {
let #(a_score, _) = a
let #(b_score, _) = b
int.compare(a_score, b_score)
}

fn make_grid(size: Int, bytes: List(Coord)) -> Grid {
let grid =
list.range(0, size)
|> list.flat_map(fn(x) {
list.range(0, size)
|> list.map(fn(y) { #(#(x, y), ".") })
})
|> dict.from_list

list.fold(bytes, grid, fn(g, c) { dict.insert(g, c, "#") })
}

fn coord_p() -> Parser(Coord) {
use a <- party.do(parser.int())
use <- party.drop(party.string(","))
use b <- party.map(parser.int())

#(a, b)
}

fn input_p() -> Parser(List(Coord)) {
party.sep1(coord_p(), party.string("\n"))
}

fn neighbors(grid: Grid, coord: Coord) -> List(Coord) {
let #(x, y) = coord
[#(x + 1, y), #(x - 1, y), #(x, y + 1), #(x, y - 1)]
|> list.filter(fn(c) { dict.get(grid, c) == Ok(".") })
}

fn steps(grid: Grid, q: Queue(Node), goal: Coord, seen: Set(Coord)) -> Int {
case pq.pop(q) {
Error(_) -> -1
Ok(#(#(score, coord), _)) if coord == goal -> score
Ok(#(node, q)) -> {
let #(score, coord) = node
case set.contains(seen, coord) {
True -> steps(grid, q, goal, seen)
False -> {
let seen = set.insert(seen, coord)
let q =
grid
|> neighbors(coord)
|> list.filter_map(fn(c) {
case set.contains(seen, c) {
True -> Error(Nil)
False -> Ok(#(score + 1, c))
}
})
|> list.fold(q, pq.push)

steps(grid, q, goal, seen)
}
}
}
}
}

fn timeline(grid: Grid, bytes: List(Coord)) -> Yielder(#(Coord, Grid)) {
case bytes {
[] -> yielder.empty()
[h, ..t] -> {
let grid = dict.insert(grid, h, "#")
use <- yielder.yield(#(h, grid))
timeline(grid, t)
}
}
}

pub fn part1(input: String, size: Int, n: Int) -> Int {
let bytes = input |> parser.go(input_p()) |> list.take(n)
let grid = make_grid(size, bytes)
let q = pq.from_list([#(0, #(0, 0))], order)

steps(grid, q, #(size, size), set.new())
}

pub fn part2(input: String, size: Int) -> String {
let bytes = parser.go(input, input_p())
let grid = make_grid(size, [])
let q = pq.from_list([#(0, #(0, 0))], order)
let goal = #(size, size)

grid
|> timeline(bytes)
|> yielder.find_map(fn(p) {
let #(#(x, y), grid) = p
case steps(grid, q, goal, set.new()) {
-1 -> Ok(int.to_string(x) <> "," <> int.to_string(y))
_ -> Error(Nil)
}
})
|> result.unwrap("")
}
41 changes: 41 additions & 0 deletions test/aoc/year2024/day18_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import aoc/year2024/day18
import glacier/should

const input = "5,4
4,2
4,5
3,0
2,1
6,3
2,4
1,5
0,6
3,3
2,6
5,1
1,2
5,5
2,5
6,5
1,4
0,4
6,4
1,1
6,1
1,0
0,5
1,6
2,0
"

pub fn part1_test() {
input
|> day18.part1(6, 12)
|> should.equal(22)
}

pub fn part2_test() {
input
|> day18.part2(6)
|> should.equal("6,1")
}

0 comments on commit 64d63f2

Please sign in to comment.