はじめに
Advent of code 2024 Day 5 の Part 2 を解きます
問題文はこちら
実装したノートブックはこちら
Part 1 はこちら
セットアップ
Kino AOC をインストールします
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Kino AOC の使い方はこちらを参照
入力の取得
"Advent of Code Helper" スマートセルを追加し、 Day 5 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
回答
入力の読込処理は Part 1 と同じです
Part 2 では誤っている更新について修正する必要があります
誤った更新の探索は Part 1 の逆を実行すればよいだけなので、末尾に |> then(&(not &1))
をつけるだけです
修正処理では、前後関係が誤っている箇所について、位置を入れ替えます
入れ替えた結果、以前は正しかった前後関係が誤った状態になる可能性があるため、修正した場合は改めて先頭のルールからチェックし直す必要があります
再帰処理が必要なため、モジュール化しました
defmodule Fixer do
def get_wrong_updates(updates, rules) do
updates
|> Enum.filter(fn update ->
rules
|> Enum.reduce_while(nil, fn {a, b}, _ ->
a_index = Enum.find_index(update, &(&1 ==a))
b_index = Enum.find_index(update, &(&1 ==b))
if is_nil(a_index) or is_nil(b_index) do
{:cont, true}
else
if a_index < b_index do
{:cont, true}
else
{:halt, false}
end
end
end)
|> then(&(not &1))
end)
end
def fix_update(update, rules) do
rules
|> Enum.reduce(update, fn {a, b}, acc_update ->
a_index = Enum.find_index(acc_update, &(&1 ==a))
b_index = Enum.find_index(acc_update, &(&1 ==b))
if is_nil(a_index) or is_nil(b_index) do
acc_update
else
if a_index < b_index do
acc_update
else
acc_update
|> List.update_at(a_index, fn _ -> b end)
|> List.update_at(b_index, fn _ -> a end)
|> fix_update(rules)
end
end
end)
end
end
入力例に対して実行してみます
updates
|> Fixer.get_wrong_updates(rules)
|> Enum.map(fn update ->
Fixer.fix_update(update, rules)
end)
|> Enum.map(fn update ->
Enum.at(update, div(length(update), 2))
end)
|> Enum.sum()
実行結果
123
問題文と同じ値になりました
実際の入力に対して実行します
{rules, updates} = parse_input.(puzzle_input)
updates
|> Fixer.get_wrong_updates(rules)
|> Enum.map(fn update ->
Fixer.fix_update(update, rules)
end)
|> Enum.map(fn update ->
Enum.at(update, div(length(update), 2))
end)
|> Enum.sum()
まとめ
問題文から ChatGPT に画像を生成してもらいました
修正処理で再帰的なチェックが必要で、そこで少し躓きました