Day 6 - Advent of Code 2023
Mix.install([:kino, :benchee])
Links
Input
input = Kino.Input.textarea("Please paste your input file:")
input = input |> Kino.Input.read()
# input = AdventOfCode.Input.get!(6, 2023)
"Time: 48 87 69 81\nDistance: 255 1288 1117 1623"
Solution
defmodule Day06 do
defdelegate parse(input), to: __MODULE__.Input
def part1(input) do
input
|> parse()
|> Enum.zip()
|> Enum.map(&calc_num_ways/1)
|> Enum.product()
end
def part2(input) do
input
|> parse()
|> Enum.map(&(&1 |> Enum.join() |> String.to_integer()))
|> List.to_tuple()
|> calc_num_ways()
end
def calc_num_ways({b, c}) do
low = (b - :math.sqrt(b * b - 4 * c)) / 2
high = (b + :math.sqrt(b * b - 4 * c)) / 2
ceil(high) - floor(low) - 1
end
defmodule Input do
def parse(input) when is_binary(input) do
~r/Time:\s*([\d\s]+)\nDistance:\s*([\d\s]+)/
|> Regex.run(input, capture: :all_but_first)
|> parse()
end
def parse(input) do
input
|> Enum.map(&parse_line/1)
end
def parse_line(line) do
line
|> String.split(" ", trim: true)
|> Enum.map(&String.to_integer/1)
end
end
end
{:module, Day06, <<70, 79, 82, 49, 0, 0, 12, ...>>,
{:module, Day06.Input, <<70, 79, 82, ...>>, {:parse_line, 1}}}
Determine the number of ways you could beat the record in each race. What do you get if you multiply these numbers together?
Your puzzle answer was 252000
.
Day06.part1(input)
252000
How many ways can you beat the record in this one much longer race?
Your puzzle answer was 36992486
.
Day06.part2(input)
36992486
Both parts of this puzzle are complete! They provide two gold stars: **
At this point, you should return to your Advent calendar and try another puzzle.
If you still want to see it, you can get your puzzle input.
Tests
ExUnit.start(auto_run: false)
defmodule Day06Test do
use ExUnit.Case, async: false
setup_all do
[
input: "Time: 7 15 30\nDistance: 9 40 200"
]
end
describe "part1/1" do
test "returns expected value", %{input: input} do
assert Day06.part1(input) == 288
end
end
describe "part2/1" do
test "returns expected value", %{input: input} do
assert Day06.part2(input) == 71503
end
end
end
ExUnit.run()
..
Finished in 0.00 seconds (0.00s async, 0.00s sync)
2 tests, 0 failures
Randomized with seed 924235
%{total: 2, failures: 0, excluded: 0, skipped: 0}
Benchmarking
# https://github.com/bencheeorg/benchee
Benchee.run(
%{
"Part 1" => fn -> Day06.part1(input) end,
"Part 2" => fn -> Day06.part2(input) end
},
memory_time: 2,
reduction_time: 2
)
nil
Warning: the benchmark Part 1 is using an evaluated function.
Evaluated functions perform slower than compiled functions.
You can move the Benchee caller to a function in a module and invoke `Mod.fun()` instead.
Alternatively, you can move the benchmark into a benchmark.exs file and run mix run benchmark.exs
Warning: the benchmark Part 2 is using an evaluated function.
Evaluated functions perform slower than compiled functions.
You can move the Benchee caller to a function in a module and invoke `Mod.fun()` instead.
Alternatively, you can move the benchmark into a benchmark.exs file and run mix run benchmark.exs
Operating System: macOS
CPU Information: Apple M1 Pro
Number of Available Cores: 10
Available memory: 32 GB
Elixir 1.15.6
Erlang 26.1
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 2 s
reduction time: 2 s
parallel: 1
inputs: none specified
Estimated total run time: 22 s
Benchmarking Part 1 ...
Benchmarking Part 2 ...
Name ips average deviation median 99th %
Part 1 432.90 K 2.31 μs ±519.91% 2.17 μs 2.58 μs
Part 2 380.22 K 2.63 μs ±449.47% 2.50 μs 2.92 μs
Comparison:
Part 1 432.90 K
Part 2 380.22 K - 1.14x slower +0.32 μs
Memory usage statistics:
Name Memory usage
Part 1 2.62 KB
Part 2 2.88 KB - 1.10x memory usage +0.26 KB
**All measurements for memory usage were the same**
Reduction count statistics:
Name Reduction count
Part 1 303
Part 2 395 - 1.30x reduction count +92
**All measurements for reduction count were the same**
nil