ElixirでHHKB プログラミングコンテスト 2020に参加してみる

# はじめに

- [Elixir](https://elixir-lang.org/)でやってみました
- いつも過去問のA〜Cまでをしかもものすごく時間をかけて解いているだけですが、2020/10/10(土) 21:00〜開催された[HHKB プログラミングコンテスト 2020](https://atcoder.jp/contests/hhkb2020)に出場してみました
- 初出場です
- Cまではクリアしたいとおもいましたが、時間内にはBまででした:man:
- トップの方は30分くらいで全部解いているようでただただすごいなあとおもっています

# 問題
- [HHKB プログラミングコンテスト 2020](https://atcoder.jp/contests/hhkb2020)
- A〜Cまで解いてみます

# 準備
- [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)等ご参考にしてください
- プロジェクトを作っておきます

```console
$ mix new at_corder
$ cd at_corder
```

# [問題A - Keyboard](https://atcoder.jp/contests/hhkb2020/tasks/hhkb2020_a)
- 問題文はリンク先をご参照くださいませ :bow:
- 時間内に解けました！

```elixir:lib/hhkb2020_a.ex
defmodule HHKB2020A do
  def main do
    s = IO.read(:line) |> String.trim()
    t = IO.read(:line) |> String.trim()

    solve(s, t)
    |> IO.puts()
  end

  @doc ~S"""
  https://atcoder.jp/contests/hhkb2020/tasks/hhkb2020_a

  ## Examples

      iex> HHKB2020A.solve("Y", "a")
      "A"
      iex> HHKB2020A.solve("N", "b")
      "b"

  """
  def solve(s, t) when s == "Y", do: String.upcase(t)

  def solve(_s, t), do: t
end
```

- `## Examples`のところに書いてあるものは、[Doctests](https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#doctests)と呼ばれるものでしてテストができます
    - 詳しくは[ExUnit.DocTest](https://hexdocs.pm/ex_unit/ExUnit.DocTest.html)をご参照ください
- 解答のキモとなる関数について、問題に書いてある入力例をインプットして出力例の通りアウトプットされるかを確かめています
- `test/at_coder_test.exs`に設定を足しておきましょう

```elixir:test/at_coder_test.exs
defmodule AtCoderTest do
  use ExUnit.Case
  doctest HHKB2020A
```

```console
$ mix test
..........

Finished in 0.2 seconds
9 doctests, 1 test, 0 failures
```

- [提出](https://atcoder.jp/contests/hhkb2020/submissions/17292199)の際にはモジュール名は`Main`にしておいてください
- :tada::tada::tada:
- この調子で以下、B問題、C問題を解いていきます

# [問題B - Futon](https://atcoder.jp/contests/hhkb2020/tasks/hhkb2020_b)
- 問題文はリンク先をご参照くださいませ :bow:
- 時間内に解けました！

```elixir:lib/hhkb2020_a.ex
defmodule HHKB2020B do
  def main do
    [h, w] =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)

    list_of_lists = for(_ <- 1..h, do: IO.read(:line) |> String.trim() |> String.codepoints())

    transposed =
      for(j <- 0..(w - 1), i <- 0..(h - 1), do: Enum.at(list_of_lists, i) |> Enum.at(j))
      |> Enum.chunk_every(h)

    solve(list_of_lists)
    |> Kernel.+(solve(transposed))
    |> IO.puts()
  end

  @spec solve(any) :: any
  @doc ~S"""
  https://atcoder.jp/contests/hhkb2020/tasks/hhkb2020_b

  ## Examples

      iex> HHKB2020B.solve([~w(. . #), ~w(# . .)])
      2
      iex> HHKB2020B.solve([~w(. #), ~w(. .), ~w(# .)])
      1
      iex> HHKB2020B.solve([~w(. #), ~w(# .)])
      0

  """
  def solve(list_of_lists) do
    Enum.map(list_of_lists, &Enum.chunk_every(&1, 2, 1, :discard))
    |> Enum.reduce(0, fn list_of_lists, acc ->
      list_of_lists
      |> Enum.count(fn [a, b] -> a == "." && b == "." end)
      |> Kernel.+(acc)
    end)
  end
end
```

- [提出](https://atcoder.jp/contests/hhkb2020/submissions/17304076)の際にはモジュール名は`Main`にしておいてください
- :tada::tada::tada:
- ここまで開始から30分くらいたっていました
- トップの方はもうそろそろF問題が終わりそうな時間だったということです:rocket::rocket::rocket:


# [問題C - Neq Min](https://atcoder.jp/contests/hhkb2020/tasks/hhkb2020_c)
- 問題文はリンク先をご参照くださいませ :bow:
- あと残り60分ありましたが時間内には終わりませんでした
- 居残りで解けました
    - [IO.puts/2](https://hexdocs.pm/elixir/IO.html#puts/2)の呼び出しを1回にしたのが効果が大きかったです
    - もうひとつは`acc_range`ってかいてあるところを毎回`0..200_001`とやるとタイムアウトでパスできませんでした
    - 効果が絶大だったのは[IO.puts/2](https://hexdocs.pm/elixir/IO.html#puts/2)の呼び出しを1回にしたほうです


```elixir:lib/hhkb2020_c.ex
defmodule HHKB2020C do
  @range 0..200_001

  def main do
    IO.read(:line)

    IO.read(:line)
    |> String.trim()
    |> String.split(" ")
    |> Enum.map(&String.to_integer/1)
    |> solve()
    |> Enum.join("\n")
    |> IO.puts()
  end

  @doc ~S"""
  https://atcoder.jp/contests/hhkb2020/tasks/hhkb2020_c

  ## Examples

      iex> HHKB2020C.solve([1, 1, 0, 2])
      [0, 0, 2, 3]

      iex> HHKB2020C.solve([5, 4, 3, 2, 1, 0, 7, 7, 6, 6])
      [0, 0, 0, 0, 0, 6, 6, 6, 8, 8]

  """
  def solve(list) do
    Enum.reduce(list, {[], %{}, 0, @range}, fn p, {acc_list, acc_map, acc_min, acc_range} ->
      acc_map = Map.put(acc_map, p, true)

      if Map.get(acc_map, acc_min) == nil do
        {[acc_min | acc_list], acc_map, acc_min, acc_range}
      else
        min =
          acc_range
          |> Enum.find(nil, fn i ->
            case Map.fetch(acc_map, i) do
              {:ok, true} -> false
              :error -> true
            end
          end)

        {[min | acc_list], acc_map, min, min..200_001}
      end
    end)
    |> elem(0)
    |> Enum.reverse()
  end
end
```

- [提出](https://atcoder.jp/contests/hhkb2020/submissions/17320912)の際にはモジュール名は`Main`にしておいてください
- Rubyでも書いてみました
    - [パス](https://atcoder.jp/contests/hhkb2020/submissions/17320153)しています

```ruby
hash = {}
 
gets.to_i
result = gets.split.map(&:to_i).inject([[], 0]) do |(acc_list, acc_min), item|
  hash[item] = item
  if hash[acc_min].nil?
    [acc_list << acc_min, acc_min]
  else
    value = (acc_min..200001).find { |i| hash[i].nil? }
    [acc_list << value, value]
  end
end
 
result[0].each { |v| puts v }
```


# Wrapping Up :qiita-fabicon: 
- とにかく[Elixir](https://elixir-lang.org/)を書くことを楽しんでいます
- Enjoy [Elixir](https://elixir-lang.org/)!!! :fire::rocket::rocket::rocket: