Skip to content

Commit 9cf10cf

Browse files
committed
Solve 2016/24
1 parent 14883ab commit 9cf10cf

3 files changed

Lines changed: 130 additions & 0 deletions

File tree

lib/2016/day_24.ex

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
defmodule AdventOfCode.Y2016.Day24 do
2+
@moduledoc """
3+
--- Day 24: Air Duct Spelunking ---
4+
Problem Link: https://adventofcode.com/2016/day/24
5+
Difficulty: m
6+
Tags: graph shortest-path tsp grid matrix
7+
"""
8+
alias AdventOfCode.Helpers.{InputReader, Transformers}
9+
alias Yog.Builder.Grid
10+
alias Yog.Pathfinding.Matrix
11+
12+
def input, do: InputReader.read_from_file(2016, 24)
13+
14+
def run(input \\ input()) do
15+
# Build the graph and identify POIs (0-7).
16+
{graph, pois} = parse(input)
17+
18+
# Pre-calculate distances between all POIs using the Matrix API.
19+
# It intelligently selects Dijkstra or Floyd-Warshall.
20+
poi_ids = Map.values(pois)
21+
{:ok, dist_matrix} = Matrix.distance_matrix(graph, poi_ids)
22+
23+
# Simplified label-based distance map.
24+
label_to_id = Map.new(pois, fn {label, id} -> {id, label} end)
25+
26+
distances =
27+
Map.new(dist_matrix, fn {{u, v}, d} ->
28+
{{label_to_id[u], label_to_id[v]}, d}
29+
end)
30+
31+
max_poi = Map.keys(pois) |> Enum.max()
32+
targets = Enum.to_list(1..max_poi)
33+
34+
{solve_tsp(targets, distances, false), solve_tsp(targets, distances, true)}
35+
end
36+
37+
def parse(data \\ input()) do
38+
# Grid builder creates an undirected graph and identifies walls.
39+
grid_data = Transformers.lines(data) |> Enum.map(&String.graphemes/1)
40+
grid = Grid.from_2d_list(grid_data, :undirected, Grid.avoiding("#"))
41+
graph = Grid.to_graph(grid)
42+
43+
# Extract positions of numbered POIs.
44+
pois =
45+
Enum.reduce(graph.nodes, %{}, fn {id, data}, acc ->
46+
case Integer.parse(data) do
47+
{label, ""} -> Map.put(acc, label, id)
48+
_ -> acc
49+
end
50+
end)
51+
52+
{graph, pois}
53+
end
54+
55+
defp solve_tsp(targets, distances, return_to_start?) do
56+
targets
57+
|> permutations()
58+
|> Enum.map(fn p ->
59+
path = if return_to_start?, do: [0 | p] ++ [0], else: [0 | p]
60+
calculate_path_dist(path, distances)
61+
end)
62+
|> Enum.min()
63+
end
64+
65+
defp calculate_path_dist(path, distances) do
66+
path
67+
|> Enum.chunk_every(2, 1, :discard)
68+
|> Enum.map(fn [a, b] -> distances[{a, b}] end)
69+
|> Enum.sum()
70+
end
71+
72+
defp permutations([]), do: [[]]
73+
74+
defp permutations(list) do
75+
for x <- list, rest <- permutations(list -- [x]), do: [x | rest]
76+
end
77+
end

priv/input_files/2016_24.txt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#########################################################################################################################################################################################
2+
#.#.....#.........#.....#.......#.#...........#...#.....................#...................#.....#.......#.#...#...................#...#...........#...#...#...#...#...#...#.....#...#.#
3+
#.###.#.#.###.#.#.#.#.#.#########.#.#.###.#.#.#.###.#.#.#.#####.#.###.###.#.###.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.#.###.###.#.#.#.#.#.#.###.###.#.#.#.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.#
4+
#.#...#.#...#...#...#.........#...#...#...#.............#.......#.....#.....#...#.#.......#.......#.........#.#.#...#...#...#.....#...#...#.#.#.#..3#.....#.........#.#...#.....#.#...#.#
5+
#.#.#.#.#.#.#.#.#.#.#.###.###.#.#####.#.#.#####.#.###.#####.#.###.#.###.#.###.#####.###.###.#.###.#.#.#.###.#####.###.###.###.#.###.#.#####.#.###.#.#.###.###.#.###.#.###.#.###.###.#.#.#
6+
#.....#.....#...#.....#...#.#.#.#...#...#...#.#...#...#.......#...#.....#...#.....#.......#.#...#.....#...#.#...#.....#.....#.#.#...#.#.......#.......#...#...#.#.#.#.#.#...#.......#.#.#
7+
#.###.#.###.#.###.#.#.#.#.#.#####.#.#.#.#####.#.#.#.#.#.#.#.###.#.#.###.#.#.#.###.###.###.#.###.#.#.#.###.#.#.###.#.#####.#.#.#.#.#.#.#.#####.#.#.#.###.#.#.#.###.#.#.#.###.#.#######.#.#
8+
#...#.#.#5#.#.........#.....#.....#.#.#.#...........#.#.....#.#...#.........#.....#...#.#...#.#.#.#...#.....#...#.#.....#...#...#.#.#...#.#.....#...#...#.....#.......#...#...#.....#...#
9+
#.#.#.###.#.#########.###.#.###.#.#.#.###.#.#######.#.#.#.#.#.#.#######.###.#.#.#.#.###.#.###.#.#.#.###.#.#####.###.###.###.#.#.#.#.#.#.#.###.#####.#######.#.#.#.###.#.#.###.#.###.###.#
10+
#...#.#.......#.#.......#.#...#...#.....#.#.#.....#.#...#...#...#.....#.....#.#...#.#.........#.....#...........#.......#.....#...#.#.....#.......#.#...#...#.#.......#.#.#.#.#.........#
11+
###.#.#.###.#.#.#.#.#.#.#.#.#.#.#######.#.#.#.#.###.#.#.###.#.#.#.#.#.#.#####.#####.#.#.#.###.#.#####.#.#.#.###.#.#.#.###.#.#.#.#.#.#.#.#.#.#.###.###.#.#.#.#.#.#.#.#.#####.###.#######.#
12+
#.#...#.#...#.#.....#...#...#...#.....#.........#.............#.......#.............#.........#.......#...#...#...#.......#.....#.......#...#.....#.....#.........#.#.#...#.#...#.....#6#
13+
#.#.#.#.###.#.#.###.#.#.#.#.#.###.#.#.#.#.#####.#.#.###.#.###.#.#.#######.#.#####.#.#######.#####.#######.#.###.#.#####.#.#.#.#.#.#####.#.#.#.#.#.#######.###.#.###.#.#.#.#.#.#.#.#.#.#.#
14+
#...#.#...#.#...........#...#.......#...#...#.......#...#.#.....#.#.................#...#...#.#.....#.....#.#.......#...#.....#...#.#...#.......#.#.#...#.......#...#.#.#.........#.....#
15+
#####.###.#.###.#####.###.#.#.#.#####.#.###.#.#.#####.#.#.#.#.#.###.#####.###.#.#####.###.#.#.#.#.#.###.###.#######.#.#.#.#.#.#.#.#.###.###.###.###.#.#.#.#.#####.#.#.###.#.#####.###.###
16+
#...#.#.........#.#...#.#...........#.#...#...#.#...#...#...#.......#...#...#...............................#.....#...#...#.....#...#.#.#.#...#.#.......#.....#.....#.#.#...#...#...#...#
17+
###.#.#.#########.#.###.#.#.###.#######.#.###.#.#.###.#.#.###.#####.###.#.#.#####.#.#.#.#.###.###.#.#.#.#.#.#.#######.#.#.#.###.###.#.#.#.#.#.###.###.###.###.#####.#.#.#.#.###.#.#.#.#.#
18+
#.#...#.#.#.#.......#...#.....#.#...#...#.....#.............#.#...#.#...#.#.......#.......#...................#.....#.#.....#.#...#.#...#.#...#...#...#...#.....#.#...#.........#...#...#
19+
#.#.#.###.#.#########.#.#.#.#.#.#.#.#.###.#.###.#.#.#.#.#######.#.#####.#####.#.#.###.###.#.#.#.###.#####.###.#.#.#.#.#.#.###.#####.#####.#.#.#####.#######.###.#.#.#.#.#.#####.###.#.#.#
20+
#...#.#.....#.#.#4#.#...#...#.........#.#.#...#...#.#.#.....#...#.#.....#.....#.......#...#.#.#.......#...#.#...#.....#.#.....#.........#.#...#.........#...#.#...#...............#.#...#
21+
#####.#.#.###.#.#.#.#.#.###.#.#.###.###.#.#.#.#.#.#.###.###.#.#.#.#.#######.###.###.#.###.#.#####.#.###.#.#.###.#####.#.#######.#.#######.###.#.#.###.#.#.###.#.#########.#.###.#.#.###.#
22+
#...#.....#.....#.......#.#...#.#.#.#.....#...#.#.#...........#.#.............#.#.......#.#.#...........#.............#.....#.#.......#...#.....#.#...#.#...#.#.........#.#...#.#...#...#
23+
#.#.#.###.#########.#.#.#.#.#.###.###.###.#######.#.#.###.#.#.#.#.###.#.#.#.#.###.#####.###.#####.#.###.#.#.###.#.#.#.#####.#.#.#.#.###.#.#.#.###.#.###.#.#.#.#.###.###.#.#.#######.#.###
24+
#...#.....#.#.......#...#.#...#.......#.......#...#.#...#...#.#.#...........#...#.......#...#.......#.#.....#.....#...#.......#...#.........#.....#.#.#.#.#...#.#.........#...........#.#
25+
#.#.###.#.#.#.#.#.#.#.#.#.#.#.#.###.#.#.#.#.#.#.#.###.###.###.#.#.#.#####.###.#.#.#########.#.#.###.#.#.#.###.###.#.#.###.#.#.#.#.###.#.#.#.#.#.#.#.#.#.#.#.###.#.###.#.#.#.#####.#.#.#.#
26+
#.#.....#.#...#.#.#.#.#...#.......#.#...#.#.#.#...#...#.......#.......#...#...#.#...#.....#.#...#...#...#.........#...#.#.#.....#.#.....#.....#.............#...#.......#...........#...#
27+
#.#.#.#.#.#.###.###.###.###.#.###.#.#.#.#.#.#.#.#.#.#######.#####.#.#.#####.#.#.###.#.#.#####.#.#####.#.#.#.#.#.#.###.#.###.#.###.#.#.###.###.#.#.#.#.#.###.#.#.#.###.###.#.#.#####.#####
28+
#...#.........#.....#.#.....#.....#.#...#.#...#...........#.#.......#.........#...............#.#...#...#.#...#.....#.#.#.....#...#.......#...#.....#...#...#.....#...#...#...#7#.......#
29+
#.#.#.###.#######.###.#.#####.#.###.#.###.#.#######.#.#.#.#.###.###.#.#.#####.#.#.#.###.#.#.###.#.#.#####.#.#.###.#.#.#.#.#.###.#.#.#.###.#.#.###.#####.#.###.#.###.#.###.#.#.#.#######.#
30+
#...#.#.............#.#...#0..#.#...........#.#.............#...#...#...#.......#.....#...#.......#...#.....#.....#.#.#.#...#.#.#.#...#...#...#.....#.#.#...........#.....#.....#.#.....#
31+
###.#.###.#.#.#.#.#.#.###.#.#.#.###.###.#####.#.#####.###.#.#.#.#.#####.#.#.#.#####.#####.#.#.#.#.#.#####.#.#.#.#.#.#.#.#.#.#.#.#.#.#####.#.###.#####.#.#.###.#######.#.#.#.#####.#.#.#.#
32+
#.#.....#...#.......#.....#.....#...#.....#...........#...#.....#.#.....#.......#.....#.....#.............#.#...#.....#.#.........#...#...#.#.............#...#...#...#.#...#.#.......#.#
33+
#.#.#.#.#.###.###.###.#.#.#.#######.#.#.#.#####.#.###.#.###.#.#.#.#.###.#.###.#.#.###.#.#.#.#########.#.#.#.###.#.#.###.#.#######.#.###.#.#.#.#.#.#.###.#.#.#.###.#.#.#.#####.#.#.###.###
34+
#.....#...#.......#.....#...#.#.....#...#.........#...#.....#.#...#.......#...............#.#.......#.......#.#...........#.....#.......#.#.#.#.#...#.......#.....#.....#...#.......#...#
35+
#.###.###.#.#######.#.#.#.#.#.#.#.#.###.#.#######.#.###.#.#####.###.#.###.###.#####.#.###.###.#.#.#.#####.#.#.#.#########.#.#.#.#####.#.#.#.###.#.###.#.###.#.###.###.#.#.#.#.#.#.#.#.#.#
36+
#.#.#.......#.#.#...#.....#.....#.#...#.....#...#.....#.#.#...........#...#...#...#.....#...#.......#.#.....#.........#...#.#...........#.#.#...#...#......1#.....#...#.#...#...#...#...#
37+
#.#.#.#.#####.#.#.###.#####.#####.#.#.###.###.#.#####.###.#.#.#.#.#####.###.###.#.#.###.###.#######.#.###.#.#.###.#.#.#.###.#.###########.#.#.###.#######.#######.#.###.###.#.#.#.###.#.#
38+
#...#.........#.....#...#.....#.....#...#.....#.......#.#...#...#.#.......#.....#...#.........#.....#...#.#.#...............#.............#.......#.........#.........#...........#.....#
39+
#.#.#.###.#.#.#.###.###.#.#####.#####.#.###.#.###.#.#.#.###.#.#####.#.###.#.#.#.#.#.#.#.###.###.###.###.#.#.#.#.#.#.#####.###.#.#.#######.#.#.#.###.#.###.#.#.#.###.#####.###.###.#.#.###
40+
#.........#.....#.......#....2#.........#.....#.....#.#.......#.#.#.......#.#...#...........#.#.#...#...#.#...#.....#.....#.#.#.#.#.......#...#.#.#.#.........#.#.........#.#...#...#.#.#
41+
#########################################################################################################################################################################################

test/2016/day_24_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
defmodule AdventOfCode.Y2016.Day24Test do
2+
@moduledoc false
3+
4+
use ExUnit.Case, async: true
5+
@moduletag :y1624
6+
7+
alias AdventOfCode.Y2016.Day24, as: Solution
8+
9+
test "Year 2016, Day 24 run/1" do
10+
assert Solution.run() == {462, 676}
11+
end
12+
end

0 commit comments

Comments
 (0)