2次元リストの動きを眺めることをやってみた（Elixir）

# はじめに
- @nasu_onigiri さんの[2次元配列の動きを眺める関数を作った（Python）](https://qiita.com/nasu_onigiri/items/fde79a765c599f351220)を拝見しまして、私は[Elixir](https://elixir-lang.org/)でやってみようとおもいました

# 0. 準備
- [Elixir](https://elixir-lang.org/)をインストールしましょう
- 手前味噌な記事ですが、[インストール](https://qiita.com/torifukukaiou/items/d04d0273749c41eb50af#0-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)等ご参考にしてください
- プロジェクトを作っておきます

```
$ mix new list_of_lists
$ cd list_of_lists
```

# 1. ソースコードを書く
- はい、ドン :rocket::rocket::rocket:

```elixir:lib/list_of_lists.ex
defmodule ListOfLists do
  @n 3
  @m 3
  @timeout 1000

  def main do
    [head | tail] = results()

    print({head, {nil, nil}})
    Process.sleep(@timeout)

    Enum.zip(tail, for(i <- 0..(@n - 1), j <- 0..(@m - 1), do: {i, j}))
    |> Enum.zip(List.duplicate(@timeout, @n * @m))
    |> Enum.flat_map(fn {a, b} -> [a, b] end)
    |> Enum.each(&print/1)

    Enum.at(tail, -1) |> to_s(@n - 1, @m - 1, false) |> IO.puts()
  end

  defp results do
    for(i <- 0..(@n - 1), j <- 0..(@m - 1), do: {i, j})
    |> Enum.reduce([init_list_of_lists(@n, @m)], fn {i, j}, acc ->
      last =
        Enum.at(acc, -1)
        |> get_and_update_in([Access.at(i), Access.at(j)], &{&1, pow(3, i + j)})
        |> elem(1)

      acc ++ [last]
    end)
  end

  defp init_list_of_lists(n, m) do
    1..n |> Enum.map(fn _ -> List.duplicate(0, m) end)
  end

  defp print(n) when is_integer(n), do: Process.sleep(n)

  defp print({list_of_lists, {i, j}}) do
    to_s(list_of_lists, i, j)
    |> IO.puts()
  end

  defp to_s(list_of_lists, i, j, move \\ true, count \\ 5) do
    for(k <- 0..(@n - 1), l <- 0..(@m - 1), do: {k, l})
    |> Enum.map(fn {k, l} ->
      value_with_leading =
        get_in(list_of_lists, [Access.at(k), Access.at(l)])
        |> Integer.to_string()
        |> String.pad_leading(count)

      if k == i && l == j do
        "\x1b[31m#{value_with_leading}\x1b[0m"
      else
        value_with_leading
      end
    end)
    |> Enum.chunk_every(@m)
    |> Enum.map(&Enum.join/1)
    |> Enum.join("\n")
    |> (fn s -> "(#{i}, #{j})\n" <> s end).()
    |> (fn s -> if(move, do: s <> "\x1b[#{@n + 1}A", else: s) end).()
  end

  defp pow(_, 0), do: 1

  defp pow(n, m), do: n * pow(n, m - 1)
end
```

- 二次元リストの更新には、[Kernel.get_and_update_in/3](https://hexdocs.pm/elixir/Kernel.html#get_and_update_in/3)を使いました
    - こんな便利な関数をはじめて使ってみました
        - お仲間には次のようなものがあります
        - [Kernel.get_in/2](https://hexdocs.pm/elixir/Kernel.html#get_in/2)
        - [Kernel.put_in/3](https://hexdocs.pm/elixir/Kernel.html#put_in/3)
        - リンク先のサンプルをみていただくとどんなものかご理解いただけるとおもいます
    - [Designing Elixir Systems With OTP: Write Highly Scalable, Self-Healing Software With Layers](https://www.amazon.co.jp/dp/1680506617)という買ってからほとんど読めていない本にそういえば`○、✗`ゲームのデータ構造の説明で便利そうな関数を使っていたことを思い出してひっぱりだしてきてから思い出しました
    - `list_of_lists`という言い方は、[List.zip/1](https://hexdocs.pm/elixir/List.html#zip/1)の引数名で使われていて、リストの各要素がリストである場合のネイティブな言い方なのだろうと思っています
- Python版の[元記事](https://qiita.com/nasu_onigiri/items/fde79a765c599f351220)で`'\033'`つまり`ESC`は[Elixir](https://elixir-lang.org/)では`"\0x1b"`と書きます
    - [Escape characters](https://hexdocs.pm/elixir/String.html#module-escape-characters)で知りました


# 2. 実行する

```
$ iex -S mix

iex> ListOfLists.main
```

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/5b91206f-2c53-a474-7832-d5160b3a3e2d.gif)

# Wrapping Up :lgtm: :qiita-fabicon: :lgtm:
- [Elixir](https://elixir-lang.org/)は公式ドキュメントを読むのが一番！
    - ある程度慣れてきたらという前提はあるとおもいます
    - ある程度というのをもっと具体的に言うと、[Enum](https://hexdocs.pm/elixir/Enum.html#content)モジュールのほとんどの関数を、何も見ずともすらすらでてくる状態くらいかなあとおもいます
- Enjoy [Elixir](https://elixir-lang.org/) !!! :fire: :rocket: :rocket: :rocket: