$\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 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
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 はこちら