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

はじめに

Advent of Code 2025 Day 8を解いてみます。
できるだけGenerative AIsの力を使わずに解いてみます。

今年はDay 12までなのかな? あとで増えるのかな。

GitHub

Livebookのnotebook集を公開しておきます。
livebooks

参考記事

Advent of Code 2025 Day 8: Playground をRustで解いた

Day 8: Playground

問題文は、Day 8: Playgroundを読んでください。

私の解答は折りたたんでおきます。

Part 1

Part 1
  • 3D空間のジャンクションボックス(接続箱)を、距離が近い順にn回繋いでいく
  • 全ペアの二乗距離を計算しソート
  • Union-Find的にMapSetでグループ管理:
    • 両方が別グループ → 合体(MapSet.union)
    • 片方だけグループにいる → そこに追加
    • どちらもいない → 新規グループ作成
  • n回接続後、グループサイズ上位3つの積が答え
defmodule Awesome do
  def combination(_, 0), do: [[]]
  def combination([], _), do: []

  def combination([x | xs], n) do
    for(y <- combination(xs, n - 1), do: [x | y]) ++ combination(xs, n)
  end
end

defmodule AdventOfCode2025Day8Part1Solver do
  def run(list_of_lists, n) do
    sorted_list_of_lists = sort(list_of_lists)
    Enum.at(sorted_list_of_lists, -1)

    0..(n - 1)
    |> Enum.reduce([], fn i, acc ->
      [point1, point2] = Enum.at(sorted_list_of_lists, i)

      index1 = Enum.find_index(acc, fn set -> point1 in set end)
      index2 = Enum.find_index(acc, fn set -> point2 in set end)

      cond do
        index1 && index2 && index1 != index2 ->
          # 両方別グループにいる → 合体
          set1 = Enum.at(acc, index1)
          set2 = Enum.at(acc, index2)
          merged = MapSet.union(set1, set2)
          acc |> List.delete_at(max(index1, index2)) |> List.delete_at(min(index1, index2)) |> then(&[merged | &1])
  
        index1 ->
          List.update_at(acc, index1, &MapSet.put(&1, point2))
  
        index2 ->
          List.update_at(acc, index2, &MapSet.put(&1, point1))
  
        true ->
          [MapSet.new([point1, point2]) | acc]
      end
    end)
    |> Enum.sort_by(&Enum.count/1, :desc)
    |> Enum.take(3)
    |> Enum.map(&Enum.count/1)
    |> Enum.product()
  end

  defp sort(list_of_lists) do
    list_of_lists
    |> Awesome.combination(2)
    |> Enum.sort_by(fn points ->
      Enum.zip_with(points, fn [a, b] -> (a - b) ** 2 end)
      |> Enum.sum()
    end)
  end
end

defmodule AdventOfCode2025Day8Part1 do
  def run(input, n \\ 1000) do
    input
    |> parse_input()
    |> solve(n)
  end

  defp solve(list_of_lists, n) do
    AdventOfCode2025Day8Part1Solver.run(list_of_lists, n)
  end

  defp parse_input(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line
      |> String.split(",", trim: true)
      |> Enum.map(&String.to_integer/1)
    end)
  end
end

input = """
162,817,812
57,618,57
906,360,560
592,479,940
352,342,300
466,668,158
542,29,236
431,825,988
739,650,466
52,470,668
216,146,977
819,987,18
117,168,530
805,96,715
346,949,466
970,615,88
941,993,340
862,61,35
984,92,344
425,690,689
"""

AdventOfCode2025Day8Part1.run(input, 10)

Part 2

Part 2
  • 全箱が1つの回路になるまで繋ぎ続ける
  • 初期状態で全箱を個別のMapSetとして用意(Enum.map(list, &MapSet.new([&1])))
  • 距離が近い順に合体していき、グループ数が1になった瞬間でreduce_whileを停止
  • 最後に繋いだペアのX座標同士の積が答え
defmodule AdventOfCode2025Day8Part2Solver do
  def run(list_of_lists) do
    acc = Enum.map(list_of_lists, & MapSet.new([&1]))

    list_of_lists
    |> sort()
    |> Enum.reduce_while({acc, nil}, fn [point1, point2], {acc, nil} ->

      index1 = Enum.find_index(acc, fn set -> point1 in set end)
      index2 = Enum.find_index(acc, fn set -> point2 in set end)

      cond do
        index1 && index2 && index1 != index2 ->
          # 両方別グループにいる → 合体
          set1 = Enum.at(acc, index1)
          set2 = Enum.at(acc, index2)
          merged = MapSet.union(set1, set2)
          new_acc = acc |> List.delete_at(max(index1, index2)) |> List.delete_at(min(index1, index2)) |> then(&[merged | &1])

          if Enum.count(new_acc) == 1 do
            [x1, _, _] = point1
            [x2, _, _] = point2
            {:halt, {new_acc, x1 * x2}}
          else
            {:cont, {new_acc, nil}}
          end

        index1 ->
          {:cont, {List.update_at(acc, index1, &MapSet.put(&1, point2)), nil}}
  
        index2 ->
          {:cont, {List.update_at(acc, index2, &MapSet.put(&1, point1)), nil}}
      end
    end)
    |> elem(1)
  end

  defp sort(list_of_lists) do
    list_of_lists
    |> Awesome.combination(2)
    |> Enum.sort_by(fn points ->
      Enum.zip_with(points, fn [a, b] -> (a - b) ** 2 end)
      |> Enum.sum()
    end)
  end
end

defmodule AdventOfCode2025Day8Part2 do
  def run(input) do
    input
    |> parse_input()
    |> solve()
  end

  defp solve(list_of_lists) do
    AdventOfCode2025Day8Part2Solver.run(list_of_lists)
  end

  defp parse_input(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn line ->
      line
      |> String.split(",", trim: true)
      |> Enum.map(&String.to_integer/1)
    end)
  end
end

input = """
162,817,812
57,618,57
906,360,560
592,479,940
352,342,300
466,668,158
542,29,236
431,825,988
739,650,466
52,470,668
216,146,977
819,987,18
117,168,530
805,96,715
346,949,466
970,615,88
941,993,340
862,61,35
984,92,344
425,690,689
"""

AdventOfCode2025Day8Part2.run(input)

さいごに

今回は自力で全部解けました。力技で解けました。よかった :tada:

どこまでできるかわかりませんが、たまには自分で書くこともしたほうがよさそうなので、Advent of Code 2025を引き続き解いて行くことを楽しみたいと思います。

Advent of Code 2025を解くことは、闘魂活動だと思います。
あなたもぜひお好きなプログラミング言語で解いてみてください!

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