Day8
Mix.install([
{:kino_aoc, git: "https://github.com/ljgago/kino_aoc"},
{:benchee, "~> 1.0"},
{:nimble_parsec, "~> 1.0"},
{:libgraph, "~> 0.16.0"},
{:math, "~> 0.7.0"}
])
Get Input
{:ok, data} = KinoAOC.download_puzzle("2023", "8", System.fetch_env!("LB_AOC_SECRET"))
Solve
defmodule Day8 do
@instr %{L: 0, R: 1}
def out(res, t), do: IO.puts("Res #{t}: #{res}")
def run(data, part) do
data
|> String.split("\n", trim: true)
|> parse()
|> solve(part)
end
def parse([instr | net]) do
i = instr |> String.graphemes() |> Enum.map(&String.to_existing_atom/1)
n = Enum.into(net, %{}, &build_node/1)
{i, n}
end
def build_node(row) do
{n, l, r} = Regex.scan(~r/[1-9A-Z]+/, row) |> List.flatten() |> List.to_tuple()
{n, {l, r}}
end
def solve(data, :p1) do
find_end("AAA", data, :p1)
end
def solve({_iter, nodes} = data, :p2) do
nodes
|> get_start()
|> Enum.map(fn st -> find_end(st, data, :p2) end)
|> Enum.reduce(1, &Math.lcm/2)
end
def get_start(nodes) do
nodes
|> Enum.filter(fn {k, _v} -> match?(<<_, _, "A">>, k) end)
|> Enum.map(fn {k, _v} -> k end)
end
def find_end(st_node, {iter, nodes}, part) do
iter
|> Stream.cycle()
|> Enum.reduce_while({st_node, 0}, fn move, {node, cnt} ->
nxt = nodes[node] |> elem(@instr[move])
end_check(nxt, node, cnt, part)
end)
end
def end_check(_nxt, "ZZZ", cnt, :p1), do: {:halt, cnt}
def end_check(_nxt, <<_, _, "Z">>, cnt, :p2), do: {:halt, cnt}
def end_check(nxt, _, cnt, _), do: {:cont, {nxt, cnt + 1}}
end
Check
ExUnit.start(autorun: false)
defmodule Day8.Test do
use ExUnit.Case, async: false
@td1 """
LLR
AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)
"""
@td2 """
LR
11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
"""
setup do
{:ok, data} = KinoAOC.download_puzzle("2023", "8", System.fetch_env!("LB_AOC_SECRET"))
%{data: data}
end
test "solves test cases" do
assert Day8.run(@td1, :p1) == 6
assert Day8.run(@td2, :p2) == 6
end
test "solves live cases", %{data: data} do
assert Day8.run(data, :p1) == 18023
assert Day8.run(data, :p2) == 14_449_445_933_179
end
end
ExUnit.run()
data |> Day8.run(:p1) |> Day8.out("p1")
data |> Day8.run(:p2) |> Day8.out("p2")