はじめに
Advent of code 2024 Day 6 の Part 1 を解きます
Part 2 の変更点が多いので別記事に分割しました
問題文はこちら
実装したノートブックはこちら
セットアップ
Kino AOC をインストールします
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Kino AOC の使い方はこちらを参照
入力の取得
"Advent of Code Helper" スマートセルを追加し、 Day 6 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
回答
まずは入力例を読み込みます
sample_input =
"""
....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...
"""
|> String.trim()
Kino.Text.new(sample_input, terminal: true)
実行結果
....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...
常に右に曲がっていくため、回転する関数を定義し、直進と右折の繰り返しで経路を求めてみましょう
turn = fn input ->
input
|> String.replace("^", "<")
|> String.split("\n")
|> Enum.map(&String.codepoints(&1))
|> Enum.zip()
|> Enum.map(fn col -> col |> Tuple.to_list() |> Enum.join() end)
|> Enum.reverse()
|> Enum.join("\n")
end
ちゃんと回転できていることを確認します
[
sample_input
|> Kino.Text.new(terminal: true),
sample_input
|> turn.()
|> Kino.Text.new(terminal: true),
sample_input
|> turn.()
|> turn.()
|> Kino.Text.new(terminal: true),
sample_input
|> turn.()
|> turn.()
|> turn.()
|> Kino.Text.new(terminal: true),
]
|> Kino.Layout.grid(columns: 4)
実行結果
直進するため、正規表現で進むべき経路を補足します
<
が進んで #
で止まるため、 #
と <
の間に #
と \n
(改行)が存在しない箇所が経路です
Regex.scan(~r/#[^\n#]*</, ".#.X.#.#.X..<..")
実行結果
[["#.X..<"]]
他の #
があったとしても、最短の経路が取得できています
入力例を回転して経路を求めてみます
turned_input = turn.(sample_input)
route =
Regex.scan(~r/#[^\n#]*</, turned_input)
|> hd()
|> hd()
実行結果
"#.....<"
これを #^XXXXX
に置換すれば、通った道を X
にできます
String.replace(
turned_input,
route,
"#^" <> String.duplicate("X", String.length(route) - 2)
)
|> Kino.Text.new(terminal: true)
実行結果
.#........
.......#..
....#.....
.........#
..........
#^XXXXX...
..........
...#......
......#...
........#.
回転して直進し、上を向きました
これで次に回転すると左を向くため、あとは繰り返せば良いことになります
最終的に脱出する場合は ~r/#[^\n#]*</
に該当する箇所がなくなりため、 ~r/\.[^\n]*</
で検索します
脱出するまで回転、直進、右折を繰り返す関数を作ります
round = fn input ->
Enum.reduce_while(1..1000, input, fn _, acc_input ->
turned_input = turn.(acc_input)
case Regex.scan(~r/#[^\n#]*</, turned_input) do
[[route]] ->
{
:cont,
String.replace(
turned_input,
route,
"#^" <> String.duplicate("X", String.length(route) - 2)
)
}
_ ->
route =
Regex.scan(~r/\.[^\n]*</, turned_input)
|> hd()
|> hd()
{
:halt,
String.replace(
turned_input,
route,
String.duplicate("X", String.length(route))
)
}
end
end)
end
入力例に対して実行してみましょう
rounded = round.(sample_input)
Kino.Text.new(rounded, terminal: true)
実行結果
.#........
.XX#......
.XXXXX#...
.XXX.X....
.XXXXXXXX#
.XXX.X..X.
#XXXXX..X.
XXXX.#..X.
..#XXXXXX.
........#.
正しく経路を X
に変換できました
最後に X の数を取得します
Regex.scan(~r/X/, rounded)
|> length()
実行結果
41
同じことを実際の入力に対して実行します
Regex.scan(~r/X/, round.(puzzle_input))
|> length()
まとめ
問題文から ChatGPT に画像を生成してもらいました
Part 2 はこちら