9
2

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 15 Part 2 を Livebook で楽しむ

Last updated at Posted at 2024-11-27

はじめに

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

本記事では Day 15 の Part 2 を解きます

問題文はこちら

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

Part 1 はこちら

セットアップ

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

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

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

Nx による行列演算を導入します

入力の取得

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

スクリーンショット 2024-11-26 18.39.38.png

私の答え

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

回答

Part 2 ではカロリーも含めて行列化します

get_ingredients_tensor = fn rows ->
  rows
  |> Enum.map(fn row ->
    Regex.named_captures(
      ~r/(?<ingredient>[a-zA-Z]+): .+ (?<capacity>\-*\d+), .+ (?<durability>\-*\d+), .+ (?<flavor>\-*\d+), .+ (?<texture>\-*\d+), .+ (?<calories>\-*\d+)/,
      row
    )
    |> then(fn %{"capacity" => capacity, "durability" => durability, "flavor" => flavor, "texture" => texture, "calories" => calories} ->
      [
        String.to_integer(capacity),
        String.to_integer(durability),
        String.to_integer(flavor),
        String.to_integer(texture),
        String.to_integer(calories)
      ]
    end)
  end)
  |> Nx.tensor()
end

カロリーは使用方法が他のプロパティとは異なるため、分離しておきます

{ingredients, calories} =
  puzzle_input
  |> String.split("\n")
  |> get_ingredients_tensor.()
  |> Nx.split(4, axis: 1)

実行結果

{#Nx.Tensor<
   s32[4][4]
   [
     [5, -1, 0, 0],
     [-1, 3, 0, 0],
     [0, -1, 4, 0],
     [-1, 0, 0, 2]
   ]
 >,
 #Nx.Tensor<
   s32[4][1]
   [
     [5],
     [1],
     [6],
     [8]
   ]
 >}

Part 1 と同じく、合計が 100 になる組み合わせを全て取得します

all_combinations =
  for sprinkles <- 0..100,
      peanut_butter <- 0..100,
      frosting <- 0..100,
      sugar <- 0..100,
      sprinkles + peanut_butter + frosting + sugar == 100 do
    [sprinkles, peanut_butter, frosting, sugar]
  end

無条件に全組み合わせの合計スコアを計算します

all_products =
  all_combinations
  |> Nx.tensor()
  |> Nx.dot(ingredients)
  |> Nx.max(0)
  |> Nx.product(axes: [1], keep_axes: true)

各組み合わせについてカロリーが 500 なら 1 、それ以外なら 0 になるカロリー条件行列を生成します

valid_calories =
  all_combinations
  |> Nx.tensor()
  |> Nx.dot(calories)
  |> Nx.equal(500)

実行結果

#Nx.Tensor<
  s32[176851][1]
  [
    [0],
    [0],
    [0],
    ...
  ]
>

合計スコアとカロリー条件行列を結合して積を求めます

カロリーが 500 の組み合わせ以外はスコアが 0 になり、条件をクリアした値のうちの最大値が求められます

Nx.concatenate([all_products, valid_calories], axis: 1)
|> Nx.product(axes: [1])
|> Nx.reduce_max()

まとめ

かなりややこしい問題ですが、 Nx の力でクリアできました

9
2
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
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?