Skip to content

Commit 14883ab

Browse files
committed
Solve 2016/13
1 parent fc2843f commit 14883ab

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

lib/2016/day_13.ex

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
defmodule AdventOfCode.Y2016.Day13 do
2+
@moduledoc """
3+
--- Day 13: A Maze of Twisty Little Cubicles ---
4+
Problem Link: https://adventofcode.com/2016/day/13
5+
Difficulty: m
6+
Tags: graph implicit-graph shortest-path a-star bfs
7+
"""
8+
import Bitwise
9+
alias AdventOfCode.Helpers.InputReader
10+
alias Yog.Pathfinding.AStar
11+
alias Yog.Traversal
12+
13+
def input, do: InputReader.read_from_file(2016, 13)
14+
15+
def run(input \\ input()) do
16+
fav = parse(input)
17+
18+
{run_1(fav), run_2(fav)}
19+
end
20+
21+
defp run_1(fav) do
22+
# Target coordinate: (31, 39)
23+
# Finding shortest path using A* search from (1, 1).
24+
target = {31, 39}
25+
26+
successors = fn pos ->
27+
open_neighbors(pos, fav) |> Enum.map(fn n -> {n, 1} end)
28+
end
29+
30+
heuristic = fn {x, y} ->
31+
abs(x - target_x(target)) + abs(y - target_y(target))
32+
end
33+
34+
{:ok, dist} =
35+
AStar.implicit_a_star(
36+
from: {1, 1},
37+
is_goal: fn pos -> pos == target end,
38+
successors_with_cost: successors,
39+
heuristic: heuristic
40+
)
41+
42+
dist
43+
end
44+
45+
defp run_2(fav) do
46+
# BFS to find all unique nodes reachable within 50 steps.
47+
Traversal.implicit_fold(
48+
from: {1, 1},
49+
using: :breadth_first,
50+
initial: MapSet.new(),
51+
successors_of: fn pos -> open_neighbors(pos, fav) end,
52+
with: fn acc, pos, meta ->
53+
new_acc = MapSet.put(acc, pos)
54+
55+
# Stop exploring depth > 50.
56+
action = if meta.depth >= 50, do: :stop, else: :continue
57+
{action, new_acc}
58+
end
59+
)
60+
|> MapSet.size()
61+
end
62+
63+
defp is_wall?(x, y, fav) do
64+
if x < 0 or y < 0 do
65+
true
66+
else
67+
val = x * x + 3 * x + 2 * x * y + y + y * y + fav
68+
rem(count_ones(val), 2) != 0
69+
end
70+
end
71+
72+
defp open_neighbors({x, y}, fav) do
73+
[{x + 1, y}, {x - 1, y}, {x, y + 1}, {x, y - 1}]
74+
|> Enum.filter(fn {nx, ny} -> not is_wall?(nx, ny, fav) end)
75+
end
76+
77+
defp count_ones(0), do: 0
78+
defp count_ones(n), do: (n &&& 1) + count_ones(n >>> 1)
79+
80+
defp target_x({x, _}), do: x
81+
defp target_y({_, y}), do: y
82+
83+
def parse(data \\ input()) do
84+
data |> String.trim() |> String.trim_trailing(".") |> String.to_integer()
85+
end
86+
end

priv/input_files/2016_13.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1350

test/2016/day_13_test.exs

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

0 commit comments

Comments
 (0)