defmodule FightingSpirit do
def shout do
IO.puts "元氣ですかーーーッ!!!"
IO.puts "元氣があればなんでもできる!"
IO.puts "闘魂とは己に打ち克つこと。"
IO.puts "そして闘いを通じて己の魂を磨いていく"
IO.puts "ことだと思います。"
end
end
FightingSpirit.shout()
$\huge{元氣ですかーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います。}$
はじめに
Advent Of Code 2024をElixirで解きます。
本日はDay 7: Bridge Repair です。
Elixirで書くと一体、どんなコードになるのでしょうか。
この記事は、Elixir初心者でも取り組める内容です。
What's Advent Of Code ?
Advent of Codeは、プログラミングスキルを高めるためのアドベントカレンダー形式のパズルイベントです。初心者から上級者まで楽しめる内容で、あらゆるプログラミング言語に対応しています。企業トレーニングや大学の課題としても活用され、毎年12月に開催されます。
それでは早速答えです
それでは早速答えを披露します。
Part 1
Part 1の答えです。あなたのコードと見比べてみてください。
私の解答
o1(preview)
以下の手順で問題を解決します。
- 入力を解析し、テスト値と数値リストを抽出します。
- 各方程式について、すべての演算子の組み合わせ(+ と *)を生成します。
- 左から順に評価し、テスト値と一致するか確認します。
- テスト値と一致する方程式のテスト値を合計します。
以下にElixirコードを示します。
defmodule AdventOfCode2024Day7Part1 do
def total_calibration_result(input) do
input
|> parse_input()
|> Enum.filter(fn {target, numbers} ->
valid_equation?(target, numbers)
end)
|> Enum.map(fn {target, _} -> target end)
|> Enum.sum()
end
defp parse_input(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
[left, right] = String.split(line, ":")
target = String.trim(left) |> String.to_integer()
numbers = String.split(right) |> Enum.map(&String.to_integer/1)
{target, numbers}
end)
end
defp valid_equation?(target, numbers) do
operators = [:+, :*]
operator_permutations(length(numbers) - 1, operators)
|> Enum.any?(fn ops ->
evaluate_expression(numbers, ops) == target
end)
end
defp operator_permutations(0, _operators), do: [[]]
defp operator_permutations(n, operators) do
for op <- operators,
rest <- operator_permutations(n - 1, operators) do
[op | rest]
end
end
defp evaluate_expression([first | rest_numbers], operators) do
Enum.zip(rest_numbers, operators)
|> Enum.reduce(first, fn {num, op}, acc ->
apply_operation(acc, op, num)
end)
end
defp apply_operation(a, :+, b), do: a + b
defp apply_operation(a, :*, b), do: a * b
end
# 使用例
input = """
190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20
"""
input |> AdventOfCode2024Day7Part1.total_calibration_result() |> IO.puts()
実行方法
実行方法は次の通りです。
elixir advent_of_code_2024_day7_part1.exs
Elixirをインストールしていない方はDockerコンテナで実行することもできます。
docker run --rm -v $PWD:/app \
hexpm/elixir:1.18.0-erlang-27.2-alpine-3.21.0 \
sh -c \
"cd /app && elixir advent_of_code_2024_day7_part1.exs"
Part 2
続いて、Part 2の答えです。あなたのコードと見比べてみてください。
私の解答
o1(preview)
Part 2では、新たに連結演算子 ||
が追加されます。連結演算子は左辺と右辺の数字を結合して1つの数値にします。例えば、12 || 345
は 12345
になります。演算の評価順序は引き続き左から順です。
これにより、連結演算子を含めた3つの方程式が新たに可能になります。
手順
- 入力を解析して、テスト値と数値リストを抽出します。
- 各方程式について、すべての演算子の組み合わせ(
+
、*
、||
)を生成します。 - 演算子の組み合わせごとに、左から順に評価し、テスト値と一致するか確認します。
- テスト値と一致する方程式のテスト値を合計します。
defmodule AdventOfCode2024Day7Part2 do
def total_calibration_result(input) do
input
|> parse_input()
|> Enum.filter(fn {target, numbers} ->
valid_equation?(target, numbers)
end)
|> Enum.map(fn {target, _} -> target end)
|> Enum.sum()
end
defp parse_input(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
[left, right] = String.split(line, ":")
target = String.trim(left) |> String.to_integer()
numbers = String.split(right) |> Enum.map(&String.to_integer/1)
{target, numbers}
end)
end
defp valid_equation?(target, numbers) do
operators = [:+, :*, :||]
operator_permutations(length(numbers) - 1, operators)
|> Enum.any?(fn ops ->
evaluate_expression(numbers, ops) == target
end)
end
defp operator_permutations(0, _operators), do: [[]]
defp operator_permutations(n, operators) do
for op <- operators,
rest <- operator_permutations(n - 1, operators) do
[op | rest]
end
end
defp evaluate_expression([first | rest_numbers], operators) do
Enum.zip(rest_numbers, operators)
|> Enum.reduce(first, fn {num, op}, acc ->
apply_operation(acc, op, num)
end)
end
defp apply_operation(a, :+, b), do: a + b
defp apply_operation(a, :*, b), do: a * b
defp apply_operation(a, :||, b) do
String.to_integer("#{a}#{b}")
end
end
# 使用例
input = """
190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20
"""
input |> AdventOfCode2024Day7Part2.total_calibration_result() |> IO.inspect()
実行方法
実行方法は次の通りです。
elixir advent_of_code_2024_day7_part2.exs
Elixirをインストールしていない方はDockerコンテナで実行することもできます。
docker run --rm -v $PWD:/app \
hexpm/elixir:1.18.0-erlang-27.2-alpine-3.21.0 \
sh -c \
"cd /app && elixir advent_of_code_2024_day7_part2.exs"
私は力を手に入れた 💪💪💪
With great power comes great responsibility.
『大いなる力には、大いなる責任が伴う』
生成AIであるGitHub Copilotという力強いツールを手にいれました。別の言い方をすると、最強のタッグパートナーを得ました。
そして私のAIは一味違います。Antonio Inoki(アントニオ猪木)、つまり猪木さんです。
ちなみに私が所属するHAW International Inc.では、GitHub Copilotの利用料を会社が負担してくれます。
プロンプトを公開
こんなプロンプトを打ち込みました。参考にさらしておきます。
- --- Day 7: Bridge Repair --- The Historians take you to a familiar rope bridge over a river in the middle of a jungle. The Chief isn't on this side of the bridge, though; maybe he's on the other side?(略)
- --- Part Two --- (略)
闘魂活動
アントニオ猪木さんは、1998年4月4日闘強童夢(東京ドーム)において、4分9秒グランド・コブラツイストでドン・フライ選手を下した1引退試合2後のセレモニーで次のように「闘魂」を説明しました。
「闘魂とは己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことだと思います。」
Advent Of Codeを解くことは、まさに闘魂活動です。
参考記事
GitHub
GitHubにもリポジトリlivebooksをあげておきます。
さいごに
チャットを通じて解答を得るという体験は、単なる効率化ではなく、新たな時代の可能性を示しています。Advent of Codeは、私たちにプログラミングという闘いを通じて、己の技術と精神を磨く場を提供してくれます。そして、GitHub Copilotのような生成AIは、その闘いを支える最強のタッグパートナーです。
しかし、AIが答えを導き出すだけでは不十分です。それをどう解釈し、自分の知識として昇華するかが、私たち人間の使命です。「闘魂とは己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことだと思います。」アントニオ猪木さんのこの言葉を胸に、私たちもAIを使いこなし、新たな創造の領域へと挑んでいきましょう。
Advent of Codeは、ただのパズルイベントではありません。未来の私たちが、さらに創造的で価値ある活動に集中するための訓練の場です。この闘魂活動を通じて、AIと人間が共に高め合い、新しい可能性を切り拓いていきましょう。挑戦のその先に、きっと新たな地平が待っています! アントニオ猪木さんが夢見た「本当の世界平和」を実現させましょう!!!
元氣があれば、なんでもできる!さあ、今すぐAdvent of Codeの闘いに飛び込みましょう!