$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$
はじめに
@torifukukaiou さんの パク リスペクト記事です
Elixir Livebook で Advent of Code 2023 の問題を解いてみます
実装したノートブックはこちら
問題はこちら
Part 1 はこちら
セットアップ
Kino AOC をインストールします
Mix.install([
{:kino_aoc, "~> 0.1.5"}
])
Kino AOC の使い方はこちらを参照
入力の取得
Day 8 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
details
回答用のモジュールです
入力を扱いやすい形にするための parse
と、回答を作るための resolve
関数を持っています
defmodule Resolver do
def parse(input) do
[instructions | maps] = String.split(input, "\n\n")
instructions = String.codepoints(instructions)
maps =
maps
|> hd()
|> String.split("\n")
|> Enum.into(%{}, fn line ->
parse_map(line)
end)
{instructions, maps}
end
defp parse_map(line) do
[current, left, right] =
line
|> String.replace("=", "")
|> String.replace("(", "")
|> String.replace(")", "")
|> String.replace(",", "")
|> String.split(" ", trim: true)
|> Enum.map(&String.reverse(&1))
{current, %{"L" => left, "R" => right}}
end
def resolve(instructions, maps) do
start_points =
maps
|> Map.keys()
|> Enum.filter(fn key ->
String.starts_with?(key, "A")
end)
start_points
|> Enum.reduce(1, fn start_point, acc ->
start_point
|> step(maps, 0, instructions, 0)
|> lcm(acc)
end)
end
defp step("Z" <> _, _, _, _, acc), do: acc
defp step(current, maps, inst_index, instructions, acc) do
instruction = Enum.at(instructions, inst_index)
next = maps[current][instruction]
next_inst_index =
if inst_index == Enum.count(instructions) -1 do
0
else
inst_index + 1
end
step(next, maps, next_inst_index, instructions, acc + 1)
end
def lcm(a, b), do: div((a * b), Integer.gcd(a, b))
end
parse
は Part1 とほぼ同じですが、パターンマッチで終了(ノード名が "Z"
で終わる)を判定するため、ノード名を反転させています
defp step("Z" <> _, _, _, _, acc), do: acc
のように、先頭でのパターンマッチは有効です
スタート地点は反転したので "A"
で始まるノードになります
各スタートから移動して全てが同時にゴールするまで継続するため、答えは各スタートからゴールまでの移動回数の最小公倍数になります
Integer.gcd
で最大公約数を求めることができるため、それを利用して最小公倍数を取得します
def lcm(a, b), do: div((a * b), Integer.gcd(a, b))
まとめ
問題は非常にややこしかったのですが、結果的には Part 1 に少し手を加えるだけで解けました