6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2023

Day 22

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

Last updated at Posted at 2023-12-27

$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$

$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$

はじめに

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

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

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

問題はこちら

セットアップ

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

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

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

入力の取得

Day 9 の入力を取得します

スクリーンショット 2023-12-27 9.42.55.png

私の答え

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

details

回答用のモジュールです

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

defmodule Resolver do
  def parse(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn line ->
      line
      |> String.split(" ")
      |> Enum.map(&String.to_integer(&1))
    end)
  end

  def resolve(array_list) do
    array_list
    |> Enum.map(fn array ->
      diff_array_list =
        0..(Enum.count(array) - 1)
        |> Enum.reduce_while([array], fn _index, acc ->
          last_array = Enum.at(acc, -1)
          diff_array = diff(last_array)

          if Enum.all?(diff_array, &(&1 == 0)) do
            {:halt, acc ++ [diff_array]}
          else
            {:cont, acc ++ [diff_array]}
          end
        end)

      diff_array_list
      |> Enum.map(fn diff_array ->
        Enum.at(diff_array, -1)
      end)
      |> Enum.sum()
    end)
    |> Enum.sum()
  end

  defp diff(array) do
    {_, a_array} = List.pop_at(array, 0)
    {_, b_array} = List.pop_at(array, -1)

    Enum.zip(a_array, b_array)
    |> Enum.map(fn {a, b} ->
      a - b
    end)
  end
end

parse は単純に各行を数値の配列にして格納します

入力

0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45

パース結果

[[0, 3, 6, 9, 12, 15], [1, 3, 6, 10, 15, 21], [10, 13, 16, 21, 30, 45]]

差数列を求める関数を用意します

  defp diff(array) do
    {_, a_array} = List.pop_at(array, 0)
    {_, b_array} = List.pop_at(array, -1)

    Enum.zip(a_array, b_array)
    |> Enum.map(fn {a, b} ->
      a - b
    end)
  end

入力が [0, 3, 6, 9, 12, 15] の場合、先頭以外の [3, 6, 9, 12, 15] と末尾以外の [0, 3, 6, 9, 12] について各要素の差をとることで [3, 3, 3, 3, 3] が取得できます
(Nx を使おうかとも考えましたがやめておきました)

差数列を全ての要素が 0 になるまで求めることで、数列の配列が以下のように求められます

[[3, 6, 9, 12, 15], [3, 3, 3, 3, 3]]

次の数字は各数列の末尾の合計(この例では 15 + 3)です

まとめ

きっともっとスマートな方法があるのでは?と思いつつ、愚直に解きました

自分でババッと解いたあとに @torifukukaiou さんの回答を見ると、ちゃんと関数を分けていたりパターンマッチを上手く使っていたりで、実力の差を感じますね

私の回答はリファクタリングの余地だらけです

Part 2 はこちら

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?