Skip to content

Commit 1e92f33

Browse files
committed
Add solution for Day 17 puzzle
1 parent 7a6f2b3 commit 1e92f33

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

17/sample_input

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2413432311323
2+
3215453535623
3+
3255245654254
4+
3446585845452
5+
4546657867536
6+
1438598798454
7+
4457876987766
8+
3637877979653
9+
4654967986887
10+
4564679986453
11+
1224686865563
12+
2546548887735
13+
4322674655533

17/sol.exs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
defmodule Day17 do
2+
def read_input(file_path) do
3+
File.read!(file_path)
4+
|> String.split("\n", trim: true)
5+
|> Enum.map(fn line -> String.graphemes(line) |> Enum.map(&String.to_integer/1) end)
6+
end
7+
8+
def get_heat({x, y}, heatmap) do
9+
case heatmap |> Enum.at(x) do
10+
nil -> nil
11+
line -> Enum.at(line, y)
12+
end
13+
end
14+
15+
def apply_dir_to_pos({x, y}, {dx, dy}), do: {x + dx, y + dy}
16+
@dirs [{1, 0}, {0, -1}, {-1, 0}, {0, 1}]
17+
18+
def next_states(heatmap, {gridX, gridY}, costs, min_dist, max_dist, [
19+
{{{x, y}, _, dist}, _} | rest
20+
])
21+
when x < 0 or y < 0 or gridX <= x or gridY <= y or dist > max_dist,
22+
do: next_states(heatmap, {gridX, gridY}, costs, min_dist, max_dist, rest)
23+
24+
def next_states(heatmap, grid_lims, costs, min_dist, max_dist, [
25+
{{pos, dir, dist}, current_cost} | rest
26+
]) do
27+
new_current_cost = get_heat(pos, heatmap) + current_cost
28+
29+
if !(costs |> Map.get({pos, dir, dist}) <= new_current_cost) do
30+
new_costs = Map.put(costs, {pos, dir, dist}, new_current_cost)
31+
32+
new_pos_dir_dists =
33+
if dist < min_dist do
34+
[
35+
{{apply_dir_to_pos(pos, Enum.at(@dirs, dir)), dir, dist + 1}, new_current_cost}
36+
| rest
37+
]
38+
else
39+
[
40+
{{apply_dir_to_pos(pos, Enum.at(@dirs, dir)), dir, dist + 1}, new_current_cost}
41+
| [
42+
{{apply_dir_to_pos(pos, Enum.at(@dirs, Integer.mod(dir + 1, 4))),
43+
Integer.mod(dir + 1, 4), 1}, new_current_cost}
44+
| [
45+
{{apply_dir_to_pos(pos, Enum.at(@dirs, Integer.mod(dir + 3, 4))),
46+
Integer.mod(dir + 3, 4), 1}, new_current_cost}
47+
| rest
48+
]
49+
]
50+
]
51+
end
52+
53+
next_states(
54+
heatmap,
55+
grid_lims,
56+
new_costs,
57+
min_dist,
58+
max_dist,
59+
new_pos_dir_dists
60+
)
61+
else
62+
next_states(heatmap, grid_lims, costs, min_dist, max_dist, rest)
63+
end
64+
end
65+
66+
def next_states(_, _, costs, _, _, []), do: costs
67+
68+
def next_states(heatmap, min_dist, max_dist),
69+
do:
70+
next_states(
71+
heatmap,
72+
{length(heatmap), length(Enum.at(heatmap, 0))},
73+
%{},
74+
min_dist,
75+
max_dist,
76+
[{{{0, 1}, 3, 1}, 0}]
77+
)
78+
79+
def solve(hm, min_dist, max_dist) do
80+
hm
81+
|> next_states(min_dist, max_dist)
82+
|> Map.to_list()
83+
|> Enum.map(fn {{{x, y}, _, dist}, cost} -> {{x, y, dist}, cost} end)
84+
|> Enum.filter(fn {{x, y, dist}, _} ->
85+
dist >= min_dist and x == length(hm) - 1 and y == length(Enum.at(hm, 0)) - 1
86+
end)
87+
|> Enum.map(fn {{_, _, _}, cost} -> cost end)
88+
|> Enum.min()
89+
end
90+
91+
def partA(file_path) do
92+
file_path
93+
|> read_input()
94+
|> solve(1, 3)
95+
end
96+
97+
def partB(file_path) do
98+
file_path
99+
|> read_input()
100+
|> solve(4, 10)
101+
end
102+
end
103+
104+
IO.puts(Day17.partA("./input"))
105+
IO.puts(Day17.partB("./input"))

0 commit comments

Comments
 (0)