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

## はじめに

Advent of code 2024 Day 6 の Part 1 を解きます

:::note info
Part 2 の変更点が多いので別記事に分割しました
:::

問題文はこちら

https://adventofcode.com/2024/day/6

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2024/2024_day6_part1.livemd

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

"Advent of Code Helper" スマートセルを追加し、 Day 6 の入力を取得します

![スクリーンショット 2024-12-08 11.08.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/f1f7ae5a-2995-ab4d-86a7-e7886318625f.png)

## 私の答え

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

<details><summary>回答</summary>

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

```elixir
sample_input =
  """
  ....#.....
  .........#
  ..........
  ..#.......
  .......#..
  ..........
  .#..^.....
  ........#.
  #.........
  ......#...
  """
  |> String.trim()

Kino.Text.new(sample_input, terminal: true)
```

実行結果

```text
....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...
```

常に右に曲がっていくため、回転する関数を定義し、直進と右折の繰り返しで経路を求めてみましょう

```elixir
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
```

ちゃんと回転できていることを確認します

```elixir
[
  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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/272a5553-f985-9169-d36d-8d04a5b5c07a.png)

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

`<` が進んで `#` で止まるため、 `#` と `<` の間に `#` と `\n` (改行)が存在しない箇所が経路です

```elixir
Regex.scan(~r/#[^\n#]*</, ".#.X.#.#.X..<..")
```

実行結果

```elixir
[["#.X..<"]]
```

他の `#` があったとしても、最短の経路が取得できています

入力例を回転して経路を求めてみます

```elixir
turned_input = turn.(sample_input)

route =
  Regex.scan(~r/#[^\n#]*</, turned_input)
  |> hd()
  |> hd()
```

実行結果

```elixir
"#.....<"
```

これを `#^XXXXX` に置換すれば、通った道を `X` にできます

```elixir
String.replace(
  turned_input,
  route,
  "#^" <> String.duplicate("X", String.length(route) - 2)
)
|> Kino.Text.new(terminal: true)
```

実行結果

```text
.#........
.......#..
....#.....
.........#
..........
#^XXXXX...
..........
...#......
......#...
........#.
```

回転して直進し、上を向きました

これで次に回転すると左を向くため、あとは繰り返せば良いことになります

最終的に脱出する場合は `~r/#[^\n#]*</` に該当する箇所がなくなりため、 `~r/\.[^\n]*</` で検索します

脱出するまで回転、直進、右折を繰り返す関数を作ります

```elixir
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
```

入力例に対して実行してみましょう

```elixir
rounded = round.(sample_input)

Kino.Text.new(rounded, terminal: true)
```

実行結果

```text
.#........
.XX#......
.XXXXX#...
.XXX.X....
.XXXXXXXX#
.XXX.X..X.
#XXXXX..X.
XXXX.#..X.
..#XXXXXX.
........#.
```

正しく経路を `X` に変換できました

最後に X の数を取得します

```elixir
Regex.scan(~r/X/, rounded)
|> length()
```

実行結果

```elixir
41
```

同じことを実際の入力に対して実行します

```elixir
Regex.scan(~r/X/, round.(puzzle_input))
|> length()
```

</details>

## まとめ

問題文から ChatGPT に画像を生成してもらいました

![aoc2024_day6_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/f21f332b-12a2-ee2f-0ead-8bd0cbad57b3.png)

Part 2 はこちら

https://qiita.com/RyoWakabayashi/private/26af90614aefa7244cd2