$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$
はじめに
@torifukukaiou さんの パク リスペクト記事です
Elixir Livebook で Advent of Code 2023 の問題を解いてみます
実装したノートブックはこちら
問題はこちら
Part 1 はこちら
セットアップ
Kino AOC をインストールします
Mix.install([
{:kino_aoc, "~> 0.1.5"}
])
Kino AOC の使い方はこちらを参照
入力の取得
Day 4 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
details
回答用のモジュールです
入力を扱いやすい形にするための parse
と、回答を作るための resolve
関数を持っています
defmodule Resolver do
def parse(input) do
input
|> String.split("\n")
|> Enum.with_index()
|> Enum.into(%{}, fn {line, index} ->
[_, card] = String.split(line, ":")
[winning_card, my_card] = String.split(card, "|")
winning_card = parse_card(winning_card)
my_card = parse_card(my_card)
nuber_of_matches =
winning_card
|> Enum.count(fn winnig_number ->
Enum.member?(my_card, winnig_number)
end)
copies = get_copies(index + 1, nuber_of_matches)
{index + 1, copies}
end)
end
defp get_copies(_, 0), do: []
defp get_copies(current_index, nuber_of_matches) do
Enum.to_list((current_index + 1)..(current_index + nuber_of_matches))
end
defp parse_card(card) do
card
|> String.split(" ")
|> Enum.filter(fn value -> value != "" end)
|> Enum.map(fn value -> String.to_integer(value) end)
end
def resolve(games) do
games
|> Enum.map(fn {card_index, _} ->
get_card(games, card_index, 0)
end)
|> Enum.sum()
end
defp get_card(games, card_index, acc) do
games[card_index]
|> Enum.map(fn next_card_index ->
get_card(games, next_card_index, acc)
end)
|> Enum.sum()
|> Kernel.+(1)
end
end
今回は parse
も Part 1 から変えています
パース時点でマッチ数を取得し、カード毎に次に取得できるカードの番号の配列を設定しておきます
例
入力
Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
パース結果
%{1 => [2, 3, 4, 5], 2 => [3, 4], 3 => [4, 5], 4 => [5], 5 => [], 6 => []}
1 のカードからは 2, 3, 4, 5 のカードが取得でき、 2 のカードからは 3, 4 のカードが取得できる、という情報担っています
resolve
でパース結果の情報を再起的に処理し、最終的な枚数を取得します
再起処理の中では、自分から連なるカードの枚数 + 1(自分自身)という計算をしています
defp get_card(games, card_index, acc) do
games[card_index]
|> Enum.map(fn next_card_index ->
get_card(games, next_card_index, acc)
end)
|> Enum.sum()
|> Kernel.+(1)
end
おそらく最後から逆に計算して、計算結果を覚えておいた方が効率的に計算できそうですが、今回はそこまでやらずに愚直に毎回計算しています
まとめ
ちょっとややこしい再帰処理が出てきました
徐々に難しくなっている感じがしますね