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

AOC 2023 - Day 06

aoc2023/day06.livemd

AOC 2023 - Day 06

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

AOC Helper

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

Part 1

Code

defmodule PartOne do
  def parse_rounds(input) do
    [
      "Time:" <> times,
      "Distance:" <> distances
    ] = String.split(input, "\n")

    times =
      times
      |> String.trim()
      |> String.split(" ")
      |> Enum.reject(&amp;(&amp;1 == ""))
      |> Enum.map(&amp;String.to_integer/1)

    distances =
      distances
      |> String.trim()
      |> String.split(" ")
      |> Enum.reject(&amp;(&amp;1 == ""))
      |> Enum.map(&amp;String.to_integer/1)

    times
    |> Enum.with_index()
    |> Enum.map(fn {time, index} ->
      {time, Enum.at(distances, index)}
    end)
  end

  def test_round({time, distance}) do
    0..time
    |> Enum.to_list()
    |> Enum.filter(fn hold_ms ->
      speed_mmps = hold_ms
      remaining_ms = time - hold_ms

      speed_mmps * remaining_ms > distance
    end)
    |> Enum.count()
  end

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

  def run(input) do
    input
    |> parse_rounds()
    |> Enum.map(&amp;test_round/1)
    |> Enum.reduce(1, &amp;(&amp;1 * &amp;2))
  end
end

Test

ExUnit.start(autorun: false)

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

  @input "Time:      7  15   30
Distance:  9  40  200"
  @expected 288

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

ExUnit.run()

Solution

PartOne.solve(puzzle_input)

Part 2

Code

defmodule PartTwo do
  def parse_round(input) do
    [
      "Time:" <> times,
      "Distance:" <> distances
    ] = String.split(input, "\n")

    time =
      times
      |> String.trim()
      |> String.split(" ")
      |> Enum.reject(&amp;(&amp;1 == ""))
      |> Enum.join()
      |> String.to_integer()

    distance =
      distances
      |> String.trim()
      |> String.split(" ")
      |> Enum.reject(&amp;(&amp;1 == ""))
      |> Enum.join()
      |> String.to_integer()

    {time, distance}
  end

  def test_round({time, distance}) do
    0..time
    |> Enum.to_list()
    |> Enum.filter(fn hold_ms ->
      speed_mmps = hold_ms
      remaining_ms = time - hold_ms

      speed_mmps * remaining_ms > distance
    end)
    |> Enum.count()
  end

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

  def run(input) do
    input
    |> parse_round()
    |> test_round()
  end
end

Test

ExUnit.start(autorun: false)

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

  @input "Time:      7  15   30
Distance:  9  40  200"
  @expected 71503

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

ExUnit.run()

Solution

PartTwo.solve(puzzle_input)