Advent of code 2024 Day 14 Part 1 & Part 2 を Livebook で楽しむ

## はじめに

Advent of code 2024 Day 14 の Part 2 と Part 2 を解きます

問題文はこちら

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

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

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

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

## セットアップ

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

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

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

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

## 入力の取得

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

![スクリーンショット 2024-12-18 21.36.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/5931ad7f-5c1e-87ca-49bf-939792d0b7d5.png)

## 私の答え

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

### Part 1

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

入力例で考えます

```elixir
sample_input =
  """
  p=0,4 v=3,-3
  p=6,3 v=-1,-3
  p=10,3 v=-1,2
  p=2,0 v=2,-1
  p=0,0 v=1,3
  p=3,0 v=-2,-2
  p=7,6 v=-1,-3
  p=3,0 v=-1,-2
  p=9,3 v=2,3
  p=7,3 v=-1,2
  p=2,4 v=2,-3
  p=9,5 v=-3,-3
  """
  |> String.trim()
```

入力を初期位置と移動速度を持つロボットとして読み込みます

```elixir
parse_robots = fn input ->
  input
  |> String.split("\n")
  |> Enum.map(fn row ->
    Regex.named_captures(
      ~r/p=(?<px>\d+),(?<py>\d+) v=(?<vx>\-*\d+),(?<vy>\-*\d+)/,
      row
    )
  end)
  |> Enum.map(fn %{"px" => px, "py" => py, "vx" => vx, "vy" => vy} ->
    %{
      p: {String.to_integer(px), String.to_integer(py)},
      v: {String.to_integer(vx), String.to_integer(vy)}
    }
  end)
end
```

```elixir
robots = parse_robots.(sample_input)
```

実行結果

```elixir
[
  %{p: {0, 4}, v: {3, -3}},
  %{p: {6, 3}, v: {-1, -3}},
  %{p: {10, 3}, v: {-1, 2}},
  %{p: {2, 0}, v: {2, -1}},
  %{p: {0, 0}, v: {1, 3}},
  %{p: {3, 0}, v: {-2, -2}},
  %{p: {7, 6}, v: {-1, -3}},
  %{p: {3, 0}, v: {-1, -2}},
  %{p: {9, 3}, v: {2, 3}},
  %{p: {7, 3}, v: {-1, 2}},
  %{p: {2, 4}, v: {2, -3}},
  %{p: {9, 5}, v: {-3, -3}}
]
```

ロボットが指定回数動いた場合の位置を計算します

指定されたタイル数の範囲でループするため、現在位置はタイル数で割った余りになります

```elixir
move = fn %{p: {px, py}, v: {vx, vy}}, {tx, ty}, step ->
  {
    (px + vx * step) |> rem(tx) |> Kernel.+(tx) |> rem(tx),
    (py + vy * step) |> rem(ty) |> Kernel.+(ty) |> rem(ty)
  }
end
```

```elixir
tiles = {11, 7}
```

```elixir
0..5
|> Enum.map(fn step ->
  move.(%{p: {2, 4}, v: {2, -3}}, tiles, step)
end)
```

実行結果

```elixir
[{2, 4}, {4, 1}, {6, 5}, {8, 2}, {10, 6}, {1, 3}]
```

`%{p: {2, 4}, v: {2, -3}}` のロボットを 5 回動かした位置が問題文と一致しています

各ロボットの位置が四象限のどこに入るかを取得します

ただし、縦横中央線上にいる場合は無視します

```elixir
get_quadrants = fn points, {tx, ty} ->
  init_quadrants = %{
    {0, 0} => 0,
    {0, 1} => 0,
    {1, 0} => 0,
    {1, 1} => 0
  }

  bx = div(tx, 2)
  by = div(ty, 2)

  points
  |> Enum.reduce(init_quadrants, fn {px, py}, acc_quadrants ->
    {
      cond do
        px == bx -> nil
        px < bx -> 0
        true -> 1
      end,
      cond do
        py == by -> nil
        py < by -> 0
        true -> 1
      end
    }
    |> case do
      {nil, _} ->
        acc_quadrants

      {_, nil} ->
        acc_quadrants

      key ->
        Map.put(acc_quadrants, key, Map.get(acc_quadrants, key) + 1)
    end
  end)
end
```

```elixir
quadrants =
  robots
  |> Enum.map(fn robot ->
    move.(robot, tiles, 100)
  end)
  |> get_quadrants.(tiles)
```

実行結果

```elixir
%{{0, 0} => 1, {0, 1} => 4, {1, 0} => 3, {1, 1} => 1}
```

各象限のロボット数を掛け合わせます

```elixir
Enum.reduce(quadrants, 1, fn {_, num}, acc -> acc * num end)
```

実行結果

```elixir
12
```

タイルを `{101, 103}` として、実際の入力で計算します

```elixir
tiles = {101, 103}
```

```elixir
puzzle_input
|> parse_robots.()
|> Enum.map(fn robot ->
  move.(robot, tiles, 100)
end)
|> get_quadrants.(tiles)
|> Enum.reduce(1, fn {_, num}, acc -> acc * num end)
```

</details>

### Part 2

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

Part 1 は素直に解けばいいだけでしたが、 Part 2 ははっきり言って問題文が悪いです

「ロボットの配置がクリスマスツリーに見えるとき」というのが、どんな絵なのか示されていないため、全くの手探りになってしまいます

最終的に、実は「ロボットが１台も重ならないとき」が答えでした

ロボットの配置を視覚化する関数を用意します

```elixir
display_map = fn points, {tx, ty} ->
  0..ty-1
  |> Enum.map(fn y ->
    0..tx-1
    |> Enum.map(fn x ->
      case Enum.find(points, fn point -> point == {x, y} end) do
        nil -> " "
        _ -> "X"
      end
    end)
    |> Enum.join()
  end)
  |> Enum.join("\n")
end
```

入力例で表示してみます

```elixir
tiles = {11, 7}
```

```elixir
sample_input
|> parse_robots.()
|> Enum.map(fn robot ->
  move.(robot, tiles, 100)
end)
|> display_map.(tiles)
|> Kino.Text.new(terminal: true)
```

実行結果

```
      X  X 
           
X          
 XX        
     X     
   XX      
 X    X    
```

実際の入力でロボットが重なっていない（重複排除しても変わらない）瞬間を探索し、視覚化します

```elixir
robots = parse_robots.(puzzle_input)
tiles = {101, 103}

1..10000
|> Enum.find(fn step ->
  points =
    robots
    |> Enum.map(fn robot ->
      move.(robot, tiles, step)
    end)
    |> Enum.sort()

  Enum.uniq(points) == points
end)
|> then(fn step ->
  IO.inspect(step)

  robots
  |> Enum.map(fn robot ->
    move.(robot, tiles, step)
  end)
  |> display_map.(tiles)
  |> Kino.Text.new(terminal: true)
end)
```

実行結果

```
                         X                                                                           
                              X                                                                      
                                                                                     X         X     
                                              X                                         X            
                                                                                                     
 X             X                                                                                     
                                                                                                     
      X     X                                                       X                   X            
X                                                                         X                          
                                          X                                                          
                                                                                                     
                                                                              X                X     
                                X   X               X                              X                 
                    X                                                                                
                       X                                                        X                    
           X           X                     X                                                       
                                                   X          X                                      
                  X           X                                                                   X  
                                                                                                     
                 X                           X                                                       
                X  X                                X                                                
                                                                                                     
                                                                                                     
                            X X     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                                  
 X                                  X                             X                                  
                                    X                             X                                  
   X                                X                             X                          X       
                          X         X                             X                   X              
                                    X              X              X                                  
                               X    X             XXX             X                                  
                                    X            XXXXX            X                                  
                                    X           XXXXXXX           X                      X        X  
                                    X          XXXXXXXXX          X            X                X    
                                    X            XXXXX            X        X                         
                                    X           XXXXXXX           X                                  
                     X            X X          XXXXXXXXX          X X                            X   
                                    X         XXXXXXXXXXX         X                                  
                                    X        XXXXXXXXXXXXX        X                                  
                                    X          XXXXXXXXX          X X                  XX            
                                    X         XXXXXXXXXXX         X                                  
                                    X        XXXXXXXXXXXXX        X                                  
                      X             X       XXXXXXXXXXXXXXX       X                                  
       X                            X      XXXXXXXXXXXXXXXXX      X                                  
           X  X                     X        XXXXXXXXXXXXX        X                X                 
                                    X       XXXXXXXXXXXXXXX       X                           X      
                                    X      XXXXXXXXXXXXXXXXX      X     X                 X          
      X                             X     XXXXXXXXXXXXXXXXXXX     X          X                       
                X                   X    XXXXXXXXXXXXXXXXXXXXX    X                   X              
                                  X X             XXX             X                                  
                                    X             XXX             X      X                           
                                    X             XXX             X                                  
                                    X                             X                                  
                            X       X                             X                                  
                                    X                             X                                  
               X                    X                             X              X                   
              X         X           XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                     X            
                           X                                        X                                
                    X     X                X                          X                              
                            X                                                                        
                                                                                               X     
                         X                                      X                                    
                                                                         X   X                       
                                            X                                                        
                                                                             X        X              
                                                                                                     
                                                                                                     
   X                                            X              X                                     
                                                                                                     
                                                                                                     
                                                                                    X            X   
                                                                  X                                  
                                X                       X                                            
                                                                                                     
                      X                                                                              
                              X            X                                                         
                                                              X                                      
                                                                X                                    
                                      X                            X                    X            
                                                                                                     
                                                                                                     
                                                                         X                    X      
                                    X       X            X       X                         X         
                                                                                                     
                                   X                                X                                
                                                                          X                          
                                                                     X         X                 X   
                                        X           X                   X                            
                                                                 X    X                              
                                           X                                                         
                                                                                                     
 X    X                                                                            X                 
                                                         X                                           
                                                                                          X          
                                   X                                                        X        
                        X                                      X                          X X        
       X                                                                  X                         X
                                                                                                     
                                                                                                     
                                                                  X                                X 
                                                                         X                           
                          X                                                                          
                                                                 X                                   
           X                                                                                         
```

確かにクリスマスツリーです

</details>

## まとめ

問題文から ChatGPT に画像を生成してもらいましたが、 ChatGPT はなぜか画像ではなくアスキーアートを生成してくれました

```
          /\_/\   
         ( o.o )   ＜ イースターバニー本部
          > ^ <     
       ~~~~~~~~~~~~ 
      |  E B H Q   |   
      |   (トイレ) |   
      |____________|   
       ||||||||||||   
       ||||||||||||   
       ..............   
       ..............    ← タイル状フロア
       ...r...r.....    ← ロボットたち (r)
       ......r......    
       ..r.......r..    
       ...r..r.......   
       ...........r..    
```

可愛いからいいか

```
          /\_/\   
         ( o.o )   ＜ イースターバニー本部
          > ^ <     
```

あと、 Part 2 は問題文を修正すべきだと思う