6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 8

Advent of code 2024 Day 6 Part 1 を Livebook で楽しむ

Last updated at Posted at 2024-12-08

はじめに

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 の入力を取得します

スクリーンショット 2024-12-08 11.08.36.png

私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

回答

まずは入力例を読み込みます

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)

実行結果

スクリーンショット 2024-12-08 11.13.26.png

直進するため、正規表現で進むべき経路を補足します

< が進んで # で止まるため、 #< の間に #\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 に画像を生成してもらいました

aoc2024_day6_1.png

Part 2 はこちら

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?