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

Advent of Code 2024 - Day 01

elixir/2024/day_01.livemd

Advent of Code 2024 - Day 01

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

Introduction

2024 - Day 01

Puzzle

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2024", "1", System.fetch_env!("LB_AOC_SESSION"))

Parser

Code - Parser

defmodule Parser do
  @reg ~r/\s+/

  def parse(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn s ->
      s
      |> String.split(@reg)
      |> Enum.map(&(String.to_integer/1))
    end)
  end
end

Tests - Parser

ExUnit.start(autorun: false)

defmodule ParserTest do
  use ExUnit.Case, async: true
  import Parser

  @input """
         5   9
         4   6
         """
  @expected [[5, 9], [4, 6]]

  test "parse test" do
    actual = parse(@input)
    assert actual == @expected
  end
end

ExUnit.run()

Part One

Code - Part 1

defmodule PartOne do
  def solve(input) do
    IO.puts("--- Part One ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    input
    |> Parser.parse()
    |> Enum.reduce([[], []], fn [l, r], [ll, rl] ->
      [[l | ll], [r | rl]]
    end)
    |> Enum.map(&Enum.sort/1)
    |> Enum.zip()
    |> Enum.map(fn {a, b} -> abs(a - b) end)
    |> Enum.sum()
  end
end

Tests - Part 1

ExUnit.start(autorun: false)

defmodule PartOneTest do
  use ExUnit.Case, async: true
  import PartOne

  @input """
         3   4
         4   3
         2   5
         1   3
         3   9
         3   3
         """
  @expected 11

  test "part one" do
    actual = run(@input)
    assert actual == @expected
  end
end

ExUnit.run()

Solution - Part 1

PartOne.solve(puzzle_input)

Part Two

Code - Part 2

defmodule PartTwo do
  def solve(input) do
    IO.puts("--- Part Two ---")
    IO.puts("Result: #{run(input)}")
  end

  def run(input) do
    [list, dict] =
      input
      |> Parser.parse()
      |> Enum.reduce([[], []], fn [l, r], [ll, rl] ->
        [[l | ll], [r | rl]]
      end)
      |> then(fn [ll, rl] -> [ll, Enum.frequencies(rl)] end)

    list
    |> Enum.map(&(&1 * Map.get(dict, &1, 0)))
    |> Enum.sum()
  end
end

Tests - Part 2

ExUnit.start(autorun: false)

defmodule PartTwoTest do
  use ExUnit.Case, async: true
  import PartTwo

  @input """
         3   4
         4   3
         2   5
         1   3
         3   9
         3   3
         """
  @expected 31

  test "part two" do
    actual = run(@input)
    assert actual == @expected
  end
end

ExUnit.run()

Solution - Part 2

PartTwo.solve(puzzle_input)