Skip to content

Commit

Permalink
2023 day 17, part 2
Browse files Browse the repository at this point in the history
That took longer than it should have...
  • Loading branch information
sevenseacat committed Dec 17, 2023
1 parent 2620576 commit d354af0
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 42 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
My Elixir solutions for [Advent of Code](https://adventofcode.com/) (all years).

<!-- stars start -->
<p><a href="./lib/y2023/"><img src="https://img.shields.io/static/v1?label=2023&message=33%20stars&style=for-the-badge&color=yellow" alt="33 stars" /></a><br />
<p><a href="./lib/y2023/"><img src="https://img.shields.io/static/v1?label=2023&message=34%20stars&style=for-the-badge&color=yellow" alt="34 stars" /></a><br />
<a href="./lib/y2022/"><img src="https://img.shields.io/static/v1?label=2022&message=%E2%AD%90%EF%B8%8F%2050%20stars%20%E2%AD%90%EF%B8%8F&style=for-the-badge&color=brightgreen" alt="50 stars" /></a><br />
<a href="./lib/y2021/"><img src="https://img.shields.io/static/v1?label=2021&message=46%20stars&style=for-the-badge&color=green" alt="46 stars" /></a><br />
<a href="./lib/y2020/"><img src="https://img.shields.io/static/v1?label=2020&message=39%20stars&style=for-the-badge&color=yellow" alt="39 stars" /></a><br />
Expand Down
5 changes: 3 additions & 2 deletions lib/y2023/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

My Elixir solutions for [Advent of Code 2023](https://adventofcode.com/2023).

<!-- stars 2023 start --><img src="https://img.shields.io/static/v1?label=2023&message=33%20stars&style=for-the-badge&color=yellow" alt="33 stars" /><!-- stars 2023 end -->
<!-- stars 2023 start --><img src="https://img.shields.io/static/v1?label=2023&message=34%20stars&style=for-the-badge&color=yellow" alt="34 stars" /><!-- stars 2023 end -->

## Benchmarks

Expand Down Expand Up @@ -47,5 +47,6 @@ day 15, part 1 1.97 K 0.51 ms ±58.77% 0.47 ms 1.
day 15, part 2 0.39 K 2.57 ms ±9.13% 2.56 ms 3.05 ms
day 16, part 1 97.00 10.31 ms ±14.20% 10.08 ms 13.65 ms
day 16, part 2 2.07 483.12 ms ±2.51% 482.96 ms 503.06 ms
day 17, part 1 1.42 704.79 ms ±2.71% 713.38 ms 719.67 ms
day 17, part 1 1.28 782.35 ms ±3.06% 789.96 ms 811.18 ms
day 17, part 2 0.30 3345.17 ms ±2.14% 3345.17 ms 3395.69 ms
```
95 changes: 57 additions & 38 deletions lib/y2023/day17.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,18 @@ defmodule Y2023.Day17 do
alias Advent.Grid

def part1(grid) do
find_best_path(grid, {1, 1})
find_best_path(grid, {1, 1}, 0..3)
end

# @doc """
# iex> Day17.part2("update or delete me")
# "update or delete me"
# """
# def part2(input) do
# input
# end
def part2(grid) do
find_best_path(grid, {1, 1}, 4..10)
end

defp find_best_path(grid, {row, col}) do
defp find_best_path(grid, {row, col}, length_range) do
PriorityQueue.new()
|> add_to_queue([[{row, col, nil, 0}]])
|> search(grid, Grid.size(grid), MapSet.new())
|> add_to_queue([[{row, col, :down, 0}]])
|> add_to_queue([[{row, col, :right, 0}]])
|> search(grid, Grid.size(grid), MapSet.new(), length_range)
end

defp add_to_queue(queue, states) do
Expand All @@ -27,42 +24,42 @@ defmodule Y2023.Day17 do
end)
end

defp search(queue, grid, destination, cache) do
do_search(PriorityQueue.pop(queue), grid, destination, cache)
defp search(queue, grid, destination, cache, length_range) do
do_search(PriorityQueue.pop(queue), grid, destination, cache, length_range)
end

defp do_search({:empty, _queue}, _grid, _destination, _cache) do
defp do_search({:empty, _queue}, _grid, _destination, _cache, _straight_line_length) do
raise("No path found")
end

defp do_search(
{{:value, [{row, col, _direction, count} | _rest]}, _queue},
_grid,
{row, col},
_cache
) do
# Winner winner chicken dinner.
count
end
defp do_search({{:value, path}, queue}, grid, destination, cache, length_range) do
{row, col, _, count} = hd(path)

defp do_search({{:value, path}, queue}, grid, destination, cache) do
if MapSet.member?(cache, cache_key(path)) do
# Been here before at a lower heat loss value, ignore
search(queue, grid, destination, cache)
if {row, col} == destination && passes_final_straight_check?(path, length_range) do
# Winner winner chicken dinner.
# Grid.display(grid, Enum.map(path, fn {row, col, _, _} -> {row, col} end))
count
else
cache = MapSet.put(cache, cache_key(path))

queue
|> add_to_queue(valid_moves(path, grid))
|> search(grid, destination, cache)
cache_key = cache_key(path)

if MapSet.member?(cache, cache_key) do
# Been here before at a lower heat loss value, ignore
search(queue, grid, destination, cache, length_range)
else
cache = MapSet.put(cache, cache_key)

queue
|> add_to_queue(valid_moves(path, grid, length_range))
|> search(grid, destination, cache, length_range)
end
end
end

defp valid_moves([{row, col, direction, value} | _rest] = path, grid) do
defp valid_moves([{row, col, direction, value} | _rest] = path, grid, length_range) do
[{row - 1, col, :up}, {row + 1, col, :down}, {row, col - 1, :left}, {row, col + 1, :right}]
|> Enum.filter(&in_grid?(grid, &1))
|> Enum.reject(&backwards?(direction, &1))
|> Enum.reject(&too_far_straight?(path, &1))
|> Enum.filter(&passes_straight_check?(path, &1, length_range))
|> Enum.map(fn {row, col, dir} ->
[{row, col, dir, value + Map.fetch!(grid, {row, col})} | path]
end)
Expand All @@ -84,12 +81,34 @@ defmodule Y2023.Day17 do
{from, to} in [{:left, :right}, {:right, :left}, {:up, :down}, {:down, :up}]
end

defp too_far_straight?([{_, _, dir, _}, {_, _, dir, _}, {_, _, dir, _} | _rest], {_, _, dir}) do
true
defp passes_straight_check?(
[{_, _, from_dir, _} | _rest] = path,
{_, _, to_dir},
length_range
) do
_min..max = length_range

straight = straight_line_length(path)

cond do
from_dir == to_dir -> straight < max
from_dir != to_dir -> straight in length_range
end
end

defp passes_final_straight_check?(path, length_range) do
straight_line_length(path) in length_range
end

defp too_far_straight?(_, _), do: false
defp straight_line_length(path) do
{_, _, direction, _} = hd(path)

path
|> Enum.take_while(fn {_, _, dir, _} -> dir == direction end)
|> length
end

@spec parse_input(binary()) :: any()
def parse_input(input) do
input
|> Grid.new()
Expand All @@ -98,5 +117,5 @@ defmodule Y2023.Day17 do
end

def part1_verify, do: input() |> parse_input() |> part1()
# def part2_verify, do: input() |> parse_input() |> part2()
def part2_verify, do: input() |> parse_input() |> part2()
end
22 changes: 21 additions & 1 deletion test/y2023/day17_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Y2023.Day17Test do
doctest Day17

test "verification, part 1", do: assert(Day17.part1_verify() == 886)
# test "verification, part 2", do: assert(Day17.part2_verify() == "update or delete me")
test "verification, part 2", do: assert(Day17.part2_verify() == 1055)

@sample_input """
2413432311323
Expand All @@ -26,4 +26,24 @@ defmodule Y2023.Day17Test do
actual = Day17.parse_input(@sample_input) |> Day17.part1()
assert 102 == actual
end

test "part 2, sample 1" do
actual = Day17.parse_input(@sample_input) |> Day17.part2()
assert 94 == actual
end

test "part 2, sample 2" do
actual =
"""
111111111111
999999999991
999999999991
999999999991
999999999991
"""
|> Day17.parse_input()
|> Day17.part2()

assert 71 == actual
end
end

0 comments on commit d354af0

Please sign in to comment.