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

Day 06

2023/day06.livemd

Day 06

Mix.install(kino: "~> 0.11")

Common

import Kino.Shorts

input = read_textarea("Puzzle input", monospace: true)
lines = String.split(input, "\n")

Part 1

lines
|> Enum.map(fn line ->
  [_str | other] = String.split(line)
  Enum.map(other, &String.to_integer/1)
end)
|> Enum.zip()
|> Enum.map(fn {duration, record} ->
  1..duration
  |> Enum.map(fn press_time -> press_time * (duration - press_time) end)
  |> Enum.count(&(&1 > record))
end)
|> Enum.reduce(1, &Kernel.*/2)

Part 2

[duration, record] =
  Enum.map(lines, fn line ->
    [_str, raw_number] = String.split(line, ":", part: 2)

    raw_number
    |> String.replace(" ", "")
    |> String.to_integer()
  end)

defmodule Race do
  def find_limit(range, duration, record, match_func)
  def find_limit(limit..limit, _duration, _record, _match_func), do: limit

  def find_limit(first..last, duration, record, match_func) do
    press_time = first + div(last - first, 2)
    length = press_time * (duration - press_time)

    new_range =
      if match_func.(length, record),
        do: (press_time + 1)..last,
        else: first..press_time

    find_limit(new_range, duration, record, match_func)
  end
end

lower_limit = Race.find_limit(1..div(duration, 2), duration, record, &amp;(&amp;1 < &amp;2))
upper_limit = Race.find_limit(div(duration, 2)..duration, duration, record, &amp;(&amp;1 > &amp;2))

upper_limit - lower_limit