闘魂Elixir ── Advent of code 2023 Day 8 Part 1 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/5361b81407b15e7c2f00

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

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

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day8_part1.livemd

問題はこちら

https://adventofcode.com/2023/day/8

## セットアップ

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

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

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

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

## 入力の取得

Day 8 の入力を取得します

![スクリーンショット 2023-12-27 1.13.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/d4778371-3c46-e5a3-33da-1e4fb95c9300.png)

## 私の答え

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

<details><summary>details</summary>

回答用のモジュールです

入力を扱いやすい形にするための `parse` と、回答を作るための `resolve` 関数を持っています

```elixir
defmodule Resolver do
  def parse(input) do
    [instructions | maps] = String.split(input, "\n\n")

    instructions = String.codepoints(instructions)

    maps =
      maps
      |> hd()
      |> String.split("\n")
      |> Enum.into(%{}, fn line ->
        parse_map(line)
      end)

    {instructions, maps}
  end

  defp parse_map(line) do
    [current, left, right] =
      line
      |> String.replace("=", "")
      |> String.replace("(", "")
      |> String.replace(")", "")
      |> String.replace(",", "")
      |> String.split(" ", trim: true)

    {current, %{"L" => left, "R" => right}}
  end

  def resolve(instructions, maps) do
    step("AAA", maps, 0, instructions, 0)
  end

  defp step("ZZZ", _, _, _, acc), do: acc

  defp step(current, maps, inst_index, instructions, acc) do
    instruction = Enum.at(instructions, inst_index)

    next = maps[current][instruction]

    next_inst_index =
      if inst_index == Enum.count(instructions) - 1 do
        0
      else
        inst_index + 1
      end

    step(next, maps, next_inst_index, instructions, acc + 1)
  end
end
```

`parse` では、左右の方向指示を `instructions` 、現在地点と左に進んだ地点、右に進んだ地点の情報を持つ `maps` を返しています

入力
```
RL

AAA = (BBB, CCC)
BBB = (DDD, EEE)
CCC = (ZZZ, GGG)
DDD = (DDD, DDD)
EEE = (EEE, EEE)
GGG = (GGG, GGG)
ZZZ = (ZZZ, ZZZ)
```

パース結果
```elixir
{["R", "L"],
 %{
   "AAA" => %{"L" => "BBB", "R" => "CCC"},
   "BBB" => %{"L" => "DDD", "R" => "EEE"},
   "CCC" => %{"L" => "ZZZ", "R" => "GGG"},
   "DDD" => %{"L" => "DDD", "R" => "DDD"},
   "EEE" => %{"L" => "EEE", "R" => "EEE"},
   "GGG" => %{"L" => "GGG", "R" => "GGG"},
   "ZZZ" => %{"L" => "ZZZ", "R" => "ZZZ"}
}}
```

`maps["AAA"]["R"]` は `"CCC"` で、 `maps["CCC"]["L"]` が `"ZZZ"` というように辿れます

パースした結果を使用し、 `resolve` では maps を `"AAA"` から `"ZZZ"` まで辿ります

ただし、 `instructions` の末尾まで移動して `"ZZZ"` に辿りつかない場合、 `instructions` の先頭に戻って `"ZZZ"` に辿りつくまで繰り返します

</details>

## まとめ

いい感じの地図が作れました

Part 2 はこちら

https://qiita.com/RyoWakabayashi/items/1115287ea315d3645e11