Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day5

2024/elixir/day5.livemd

Day5

Mix.install([
  {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}
])

Setup

{:ok, data} = KinoAOC.download_puzzle("2024", "5", System.fetch_env!("LB_AOC_SECRET"))

Solve

defmodule Day5 do
  def parse(data) do
    [ord, p] = String.split(data, "\n\n", trim: true)
    {split_with(ord, "|"), split_with(p, ",")}
  end

  def split_with(str, with) do
    str
    |> String.split("\n", trim: true)
    |> Enum.map(fn r ->
      r |> String.split(with, trim: true) |> Enum.map(&String.to_integer/1)
    end)
  end

  def solve(data) do
    {ord, updates} = parse(data)

    {good, bad} =
      updates
      |> Enum.map(fn upd -> {upd, do_sort(upd, ord)} end)
      |> Enum.split_with(fn {orig, sorted} -> orig == sorted end)

    {get_res(good, :t1), get_res(bad, :t2)}
  end

  def do_sort(row, ord) do
    rank =
      ord
      |> Enum.filter(fn [a, b] -> a in row && b in row end)
      |> Enum.reduce(%{}, fn [a, b], acc ->
        acc
        |> Map.update(a, 0, fn v -> v end)
        |> Map.update(b, 1, fn v -> v + 1 end)
      end)

    row
    |> Enum.with_index()
    |> Enum.sort_by(fn {d, i} -> {rank[d], i} end)
    |> Enum.map(fn {d, _} -> d end)
  end

  def get_res(updates, :t1) do
    updates |> Enum.map(fn {orig, _} -> orig end) |> get_sum()
  end

  def get_res(updates, :t2) do
    updates |> Enum.map(fn {_, sorted} -> sorted end) |> get_sum()
  end

  def get_sum(updates) do
    updates
    |> Enum.map(fn upd ->
      mid = upd |> length() |> div(2)
      Enum.at(upd, mid)
    end)
    |> Enum.sum()
  end
end

tdata = """
47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13

75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47
"""


Day5.solve(tdata) |> IO.inspect(label: "test >>>")
Day5.solve(data) # {4185, 4480}