rugyoga
Fairly straightforward Dijkstra’s algorithm
import AOC
aoc 2023, 17 do
def compute(input, candidates) do
{{max_row, max_col}, items} = Grid.parse(input)
heat_map =
items
|> Enum.map(fn {coord, number} -> {coord, String.to_integer(number)} end)
|> Map.new
Heap.new()
|> Heap.push({0, [{{0,0}, :east}]})
|> Heap.push({0, [{{0,0}, :south}]})
|> search({max_row-1, max_col-1}, heat_map, MapSet.new, candidates)
end
def p1(input), do: compute(input, &candidates_simple/1)
def p2(input), do: compute(input, &candidates_ultra/1)
def search(heap, {row_t, col_t} = target, heat_map, seen, candidates) do
{{cost, last_3}, heap} = Heap.pop(heap)
row_col = last_3 |> hd |> elem(0)
cond do
row_col == target -> cost
MapSet.member?(seen, last_3) -> search(heap, target, heat_map, seen, candidates)
true ->
seen = MapSet.put(seen, last_3)
last_3
|> then(candidates)
|> Enum.filter(fn [{{row, col}, _} | _] -> 0 <= row and row <= row_t and 0 <= col and col <= col_t end)
|> Enum.reduce(heap, fn last_3, heap -> Heap.push(heap, {cost+heat_map[last_3 |> hd |> elem(0)], last_3}) end)
|> search(target, heat_map, seen, candidates)
end
end
def candidates_simple([x, _, _]), do: [[go(:left, x)], [go(:right, x)]]
def candidates_simple([x | rest]), do: [[go(:straight, x), x | rest], [go(:left, x)], [go(:right, x)]]
def candidates_ultra(moves) do
cond do
length(moves) < 4 -> [[go(:straight, hd(moves)) | moves]]
length(moves) == 10 -> [[go(:left, hd(moves))], [go(:right, hd(moves))]]
true -> [[go(:straight, hd(moves)) | moves], [go(:left, hd(moves))], [go(:right, hd(moves))]]
end
end
@spec go(any(), {{any(), any()}, any()}) :: {{any(), any()}, :east | :north | :south | :west}
def go(which_way, {row_col, dir}), do: next(row_col, dirs()[dir][which_way])
def dirs() do
%{west: %{left: :south, straight: :west, right: :north},
north: %{left: :west, straight: :north, right: :east},
east: %{left: :south, straight: :east, right: :north},
south: %{left: :east, straight: :south, right: :west}}
end
def next({row, col}, :west), do: {{row, col-1}, :west}
def next({row, col}, :east), do: {{row, col+1}, :east}
def next({row, col}, :north), do: {{row-1, col}, :north}
def next({row, col}, :south), do: {{row+1, col}, :south}
end
Trending in Challenges
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
bjorng
Dijkstra’s algorithm using
gb_setsas priority queue. It solves both parts in 2.7 seconds on my computer.https://github.com/bjorng/advent-of-code-2023/blob/main/day17/lib/day17.ex
EDIT:
I realized that all elements inserted into the
gb_setsare guaranteed to be unique, which means that it is safe to usegb_sets:insert/2instead ofgb_sets:add/2. That reduces the time for my solution from 2.7 seconds to 2.2 seconds.exists
Also used Dijkstra, but through libgraph. It turns out that creating graphs this big in it incurs a massive overhead, 50 seconds for part one and 130 seconds for part two (num_vertices: 39763, num_edges 529036). Well, TIL. The Dijkstra itself is then fast.
For me the interesting part was to realise that I can enforce the direction changes by having “two layers” of the grid, with top-to-bottom ony vertical direction arrows, and bottom-to-top only horizontal direction arrows.
code
I should probably try to rewrite this with just digraph to see how it compares, although digraph does not do edge weights directly.
(sorry, hit the wrong “reply” button…)
lud
A bad solution today after a long night and a day in my home town, not much time to do better, but I might try gb_sets if it can fit in my implementation without changing much.
Edit: yay! Indeed it is much faster. And correct.
Aetherus
First time coding Dijkstra’s path finding algorithm by hand in a functional programming language. I was struggling to implement Fibonacci heap and failed in the end, so I thought “do I really need decrease-key?” And that led to this solution:
igorb
I would not call it “fairly straightforward”. I found it quite difficult. I used
PriorityQueuefrom:libgraph.https://github.com/ibarakaiev/advent-of-code-2023/blob/main/lib/advent_of_code/day_17.ex
Aetherus
Reading the source code of
libgraphtruly is an amazing way of learning graphs.I remember that it used to use a pairing heap as the priority queue, now it uses
:gb_trees.midouest
Took me a while to implement Dijkstra’s Algorithm and then I got stuck because I was hung up on using x-y coordinates for the distance/previous keys. I rewrote it as a depth-first search and ran it on my desktop computer with 16GB of RAM to find the answer to part 1 in about 10 minutes! I tried the same approach for part 2, but the program consumed all of my RAM + lots of paging to disk. I restarted it a few times with the best result from the previous iteration, but it never found the answer. I eventually went back to my original implementation and finally figured out the trick. This was a nice dive into the Erlang docs to learn about
:gb_sets.Part 1
Part 2
code-shoily
You just inspired me to start the
Graphsection of my algorithm repository. Quite a readable code too! Thanks for sharing.pehbehbeh
Hat the same problem with
libgraph. After building the graph viaTask.async_streamit “only” took 13.0s for part 1 and 14.2s for part 2 in Livebook on my M2 Pro.https://github.com/pehbehbeh/adventofcode/blob/main/2023/17.livemd
Aetherus
I implemented a priority queue with a decrease-key operation and hoped it would make my solution run faster, but it didn’t because the decrease-key operation was not called even once!
Here’s my code:
https://github.com/Aetherus/advent-of-code/blob/master/2023/day-17-alt.livemd