Day 08
Mix.install([
{:kino, "~> 0.7.0"}
])
IEx.Helpers.c("/Users/johnb/dev/2023adventOfCode/advent_of_code.ex")
alias AdventOfCode, as: AOC
alias Kino.Input
# Note: when making the next template, something like this works well:
# `cat day04.livemd | sed 's/03/04/' > day04.livemd`
#
Installation and Data
input_p1example = Kino.Input.textarea("Example Data")
input_p1puzzleInput = Kino.Input.textarea("Puzzle Input")
input_source_select =
Kino.Input.select("Source", [{:example, "example"}, {:puzzle_input, "puzzle input"}])
p1data = fn ->
(Kino.Input.read(input_source_select) == :example &&
Kino.Input.read(input_p1example)) ||
Kino.Input.read(input_p1puzzleInput)
end
Part 1
defmodule Day08 do
@moduledoc """
NOTE: part 1 example was this, before being overwritten by part 2
LLR
AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)
"""
def parse_dirs_and_maps(text) do
[directions, maps] = AOC.as_doublespaced_paragraphs(text)
directions = String.split(directions, "", trim: true)
maps =
maps
|> AOC.as_single_lines()
|> Enum.reduce(%{}, fn <>,
acc ->
Map.put(acc, node, %{"L" => left, "R" => right})
end)
[directions, maps]
end
def solve(text) do
# |> IO.inspect()
[directions, maps] = parse_dirs_and_maps(text)
Stream.cycle(directions)
|> Enum.reduce_while({"AAA", 0}, fn dir, {node, steps} ->
# IO.inspect([dir, {node, steps}])
case node do
"ZZZ" -> {:halt, steps}
_ -> {:cont, {maps[node][dir], steps + 1}}
end
end)
end
def solve2(text) do
# |> IO.inspect()
[directions, maps] = parse_dirs_and_maps(text)
# filter nodes that end with A
aaaa =
Map.keys(maps)
|> Enum.filter(fn key -> key =~ ~r/..A/ end)
# |> IO.inspect()
endpoints =
Enum.reduce(aaaa, %{}, fn a_node, acc ->
original_node = a_node
{total_steps, last_node} =
Stream.cycle(directions)
|> Enum.reduce_while({a_node, 0}, fn dir, {node, steps} ->
case node =~ ~r/..Z/ do
true -> {:halt, {steps, node}}
_ -> {:cont, {maps[node][dir], steps + 1}}
end
end)
Map.put(acc, original_node, {total_steps, last_node}) |> IO.inspect()
# |> IO.inspect()
end)
|> IO.inspect()
endpoints
|> Enum.reduce(1, fn {_first_node, {steps, _last_node}}, acc -> acc * steps end)
end
end
# p1data.()
# |> Day08.solve()
# |> IO.inspect(label: "\n*** Part 1 solution (example: 6)")
# 17621
p1data.()
|> Day08.solve2()
|> IO.inspect(label: "\n*** Part 2 solution (example: )")
# 20685524831999
# hand-calculated at this point:
# "AAA" => {17621, "ZZZ"}, 67 x 263
# "CPA" => {16043, "JTZ"}, 61 x 263
# "PJA" => {20777, "FTZ"}, 79 x 263
# "QKA" => {19199, "VCZ"}, 73 x 263
# "VLA" => {18673, "GKZ"}, 71 x 263
# "VSA" => {12361, "CLZ" 47 x 263
# 47 * 71 * 73 * 79 * 61 * 67 = 78652185673
# 78652185673 * 263 = 20685524831999