호두나무 공방/Advent of Code

Advent of Code 2022 Day 13 in Elixir - Distress Signal 풀이

2023. 1. 7. 22:00

문제 보기

중첩 리스트로 주어진 패킷을 비교하는 문제였다. 첫 번째 문제는 패킷 쌍이 올바른 순서로 되어 있는지 확인하는 문제, 두 번째 문제는 전체 패킷을 올바른 순서로 정렬하는 문제였다.

재귀 문제다. 아무리 재귀를 피하려고 해도 이런 문제는 재귀를 쓸 수밖에 없다(변명). 첫 번째 문제에서 아무 생각 없이 compare 함수를 만들어 썼는데, 두 번째 문제를 보니 그냥 조금 전에 작성한 compare 함수를 그대로 정렬 함수에 넣어주면 끝이라 생각보다 문제를 너무 쉽게 풀었다.

defmodule Omicron.Day13 do
  @dir "data/day13/"

  def q1(file_name \\ "q.txt") do
    File.read!(@dir <> file_name)
    |> String.split("\n\n")
    |> Enum.with_index()
    |> Enum.map(fn {packets, i} ->
      packets
      |> String.split("\n")
      |> Enum.map(fn line ->
        {packet, _} = Code.eval_string(line)
        packet
      end)
      |> compare()
      |> IO.inspect(label: packets)
      |> then(fn v -> {v, i} end)
    end)
    |> Enum.filter(fn {v, _i} -> v == true end)
    |> Enum.map(fn {_v, i} -> i + 1 end)
    |> Enum.sum()
  end

  def q2(file_name \\ "q.txt") do
    packets =
      File.read!(@dir <> file_name)
      |> String.split("\n\n")
      |> Enum.flat_map(fn two_packets ->
        two_packets
        |> String.split("\n")
        |> Enum.map(fn line ->
          {packet, _} = Code.eval_string(line)
          packet
        end)
      end)
      |> Kernel.++([[[2]], [[6]]])
      |> Enum.sort(fn a, b -> compare([a, b]) end)

    divider_2 = packets |> Enum.find_index(fn v -> v == [[2]] end) |> Kernel.+(1)
    divider_6 = packets |> Enum.find_index(fn v -> v == [[6]] end) |> Kernel.+(1)

    divider_2 * divider_6
  end

  defp compare([[], []]), do: :pass

  defp compare([[], [_ | _]]), do: true

  defp compare([[_ | _], []]), do: false

  defp compare([[h1 | t1], [h1 | t2]]), do: compare([t1, t2])

  defp compare([[h1 | _], [h2 | _]]) when is_integer(h1) and is_integer(h2) and h1 < h2, do: true

  defp compare([[h1 | _], [h2 | _]]) when is_integer(h1) and is_integer(h2) and h1 > h2, do: false

  defp compare([[h1 | t1], [h2 | t2]]) do
    case compare([List.wrap(h1), List.wrap(h2)]) do
      true -> true
      :pass -> compare([t1, t2])
      false -> false
    end
  end
end