7
0

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 2024

Day 17

Advent of code 2015 Day 23 Part 1 & Part 2 を Livebook で楽しむ

Last updated at Posted at 2024-12-05

はじめに

Advent of code 2024 の準備として、過去回の Advent of code 2015 を Livebook で楽しみます

本記事では Day 23 の Part 1 と Part 2 を解きます

問題文はこちら

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

セットアップ

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

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

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

入力の取得

"Advent of Code Helper" スマートセルを追加し、 Day 23 の入力を取得します

スクリーンショット 2024-12-04 21.42.16.png

私の答え

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

Part 1

回答

まず小さい入力例で試してみましょう

instructions =
  """
  inc a
  jio a, +2
  tpl a
  inc a
  """
  |> String.trim()
  |> String.split("\n")

各行の命令を Elixir のコードに変換して評価する、という変則的なやり方を思いついてしまったので、それで解きました

正規表現 ~r/(?<func>[a-z]+) (?<var>[a-z]*),* *(?<offset>(\+|\-)*\d*)/ で命令の関数、変数を取得します

命令の内容を Elixir で使える形に変換します(次に評価する行を知る必要があるため、引数に index を加えています)

  • inc a -> inc.({a, index})
  • jmp 4 -> jmp.({a, index}, 4)
  • jio a, 4 -> jio.({a, index}, 4)

実際の入力には変数 b も存在するため、入出力に入れておきます

hlftpl の関数を評価するコード内に定義し、

eval_instruction = fn instruction, {a, b, index} ->
  Regex.named_captures(
    ~r/(?<func>[a-z]+) (?<var>[a-z]*),* *(?<offset>(\+|\-)*\d*)/,
    instruction
  )
  |> then(fn %{"func" => func, "var" => var, "offset" => offset} ->
    var = if var == "", do: "a", else: var

    instruction =
      cond do
        offset == "" ->
          "#{func}.({#{var}, #{index}})"
        func == "jmp" ->
          "#{func}.({a, #{index}}, #{String.to_integer(offset)})"
        true ->
          "#{func}.({#{var}, #{index}}, #{String.to_integer(offset)})"
      end
      |> IO.inspect()

    """
    hlf = fn {a, index} -> {div(a, 2), index + 1} end
    tpl = fn {a, index} -> {a * 3, index + 1} end
    inc = fn {a, index} -> {a + 1, index + 1} end
    jmp = fn {a, index}, offset -> {a, index + offset} end
    jie = fn {a, index}, offset ->
      if rem(a, 2) == 0 do
        {a, index + offset}
      else
        {a, index + 1}
      end
    end
    jio = fn {a, index}, offset ->
      case a do
        1 -> {a, index + offset}
        _ -> {a, index + 1}
      end
    end

    a = #{a}
    b = #{b}

    {#{var}, index} = #{instruction}

    {a, b, index}
    """
  end)
  |> Code.eval_string()
  |> elem(0)
end

各変数が正しく評価されるか確認していきます

実行結果は全て想定通りになります

eval_instruction.("hlf a", {4, 6, 0})
eval_instruction.("hlf b", {4, 6, 0})
eval_instruction.("tpl a", {1, 1, 0})
eval_instruction.("inc a", {0, 1, 0})
eval_instruction.("jmp 5", {0, 1, 0})
eval_instruction.("jmp -5", {0, 1, 10})
eval_instruction.("jie a, 3", {2, 1, 0})
eval_instruction.("jie a, 3", {3, 1, 0})
eval_instruction.("jio a, 3", {1, 1, 0})
eval_instruction.("jio a, 3", {2, 1, 0})

入力例に対して実行してみます

index が命令の範囲外に出るまで繰り返します

0..10
|> Enum.reduce_while({0, 0, 0}, fn _, {a, b, index} ->
  {next_a, next_b, next_index} =
    instructions
    |> Enum.at(index)
    |> eval_instruction.({a, b, index})
    |> IO.inspect()

  if next_index >= length(instructions) - 1 do
    {:halt, {next_a, next_b, next_index}}
  else
    {:cont, {next_a, next_b, next_index}}
  end
end)

実行結果

{1, 0, 3}

実際の入力に対して実行します

instructions = String.split(puzzle_input, "\n")
0..1000
|> Enum.reduce_while({0, 0, 0}, fn _, {a, b, index} ->
  {next_a, next_b, next_index} =
    instructions
    |> Enum.at(index)
    |> eval_instruction.({a, b, index})
    |> IO.inspect()

  if next_index >= length(instructions) do
    {:halt, {next_a, next_b, next_index}}
  else
    {:cont, {next_a, next_b, next_index}}
  end
end)

Part 2

回答

a の初期値を 1 にして実行するだけです

0..10000
|> Enum.reduce_while({1, 0, 0}, fn _, {a, b, index} ->
  {next_a, next_b, next_index} =
    instructions
    |> Enum.at(index)
    |> eval_instruction.({a, b, index})
    |> IO.inspect()

  if next_index >= length(instructions) do
    {:halt, {next_a, next_b, next_index}}
  else
    {:cont, {next_a, next_b, next_index}}
  end
end)

まとめ

問題文から ChatGPT に画像を生成してもらいました

aoc2015_day23.png

思ったよりすんなり解けました

メタプログラミングも面白いですね

7
0
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
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?