74 lines
1.9 KiB
Elixir
74 lines
1.9 KiB
Elixir
defmodule Mix.Tasks.Day6 do
|
|
use Mix.Task
|
|
|
|
def parse(input, :part1) do
|
|
input
|
|
|> Enum.map(fn s ->
|
|
String.split(s, " ")
|
|
|> Enum.reject(fn s -> s === "" or s === "Time:" or s === "Distance:" end)
|
|
end)
|
|
|> Enum.map(fn i ->
|
|
i
|
|
|> Enum.map(fn s ->
|
|
s |> String.trim() |> String.to_integer()
|
|
end)
|
|
end)
|
|
end
|
|
|
|
def parse(input, :part2) do
|
|
input
|
|
|> Enum.map(fn s ->
|
|
String.split(s, " ")
|
|
|> Enum.reject(fn s -> s === "" or s === "Time:" or s === "Distance:" end)
|
|
end)
|
|
|> Enum.map(fn u ->
|
|
u
|
|
|> Enum.join("")
|
|
|> String.trim()
|
|
|> String.to_integer()
|
|
end)
|
|
end
|
|
|
|
def distance_traveled_in_n_seconds(seconds, duration) do
|
|
seconds * (duration - seconds)
|
|
end
|
|
|
|
def polynomial_roots(a, b, c) do
|
|
[
|
|
(-b + :math.sqrt(b ** 2 - 4 * a * c)) / (2 * a),
|
|
(-b - :math.sqrt(b ** 2 - 4 * a * c)) / (2 * a)
|
|
]
|
|
end
|
|
|
|
def solve([time, distance], p) when p === :part2 do
|
|
# number of negative integer solutions to the polynomial
|
|
# x^2 - tx + d < 0
|
|
# where x is time spent holding button, t is the duration of the race (seconds), and d is the distance to beat
|
|
roots = polynomial_roots(1, -time, distance)
|
|
max = roots |> Enum.max()
|
|
min = roots |> Enum.min()
|
|
floor(max) - floor(min)
|
|
end
|
|
|
|
def solve([times, distances], p) when p === :part1 do
|
|
for {time, index} <- times |> Enum.with_index(),
|
|
seconds <- 1..(time - 1),
|
|
distance_traveled_in_n_seconds(seconds, time) > distances |> Enum.at(index),
|
|
reduce: %{} do
|
|
acc ->
|
|
acc |> Map.update(time, [seconds], fn u -> [seconds | u] end)
|
|
end
|
|
|> Map.values()
|
|
|> Enum.reduce(
|
|
1,
|
|
fn a, acc ->
|
|
acc * (a |> Enum.count())
|
|
end
|
|
)
|
|
end
|
|
|
|
def run(args) do
|
|
part = if args |> Enum.at(0) == "1", do: :part1, else: :part2
|
|
IO.stream() |> parse(part) |> solve(part) |> IO.puts()
|
|
end
|
|
end
|