はじめに
Advent of code 2024 の準備として、過去回の Advent of code 2015 を Livebook で楽しみます
本記事では Day 10 の Part 1 と Part 2 を解きます
問題文はこちら
実装したノートブックはこちら
セットアップ
Kino AOC をインストールします
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Kino AOC の使い方はこちらを参照
入力の取得
"Advent of Code Helper" スマートセルを追加し、 Day 10 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
Part 1
回答
正規表現 (.)\1*
は1文字以上の繰り返しに該当します
Regex.scan
により、これに該当するものを全て取得します
例えば "111221"
を入力として、以下のように処理します
Regex.scan(~r/(.)\1*/, "111221")
実行結果は以下のようになります
[["111", "1"], ["22", "2"], ["1", "1"]]
各繰り返しについて、最も長い該当箇所と、最も短い該当箇所が返ってきます
[max, min]
で取得される各繰り返しについて、 max
の長さを繰り返し回数、 min
を繰り返されている文字として扱えば問題を解くことができます
問題を解くための関数を定義します
get_char_group_list = fn input ->
Regex.scan(~r/(.)\1*/, input)
|> Enum.map(fn [max, min] ->
"#{String.length(max)}#{min}"
end)
|> Enum.join()
end
試しに "111221"
を入力として実行してみます
get_char_group_list.("111221")
結果は以下のように正しく返ってきます
"312211"
あとはこれを 40 回繰り返し、文字列長を取得するだけです
1..40
|> Enum.reduce(puzzle_input, fn _, acc_input ->
get_char_group_list.(acc_input)
end)
|> String.length()
Part 2
回答
Part 2 は、まさかの繰り返し回数を増やすだけでした
1..50
|> Enum.reduce(puzzle_input, fn _, acc_input ->
get_char_group_list.(acc_input)
end)
|> String.length()
まとめ
実は当初は文字列の繰り返しを律儀に数える実装をしていたのですが、一旦解けた後に別の解法を考えつきました
入力のパース処理はできるだけ正規表現でやった方が良いですね