Day 1 ended up being a nice, gentle introduction to the year, with a bit of flexing of some fun programmatic skills. The macro from Day 0 came in handy to really keep things small and simplified.
Puzzle 1
Puzzle 1 was pretty straightforward. Given the masses of a number of modules, calculate all the fuel required.
import AdventOfCode
aoc 2019, 1 do
def p1 do
input_stream()
|> Stream.map(&String.to_integer/1)
|> Stream.map(&simple_fuel/1)
|> Enum.sum()
end
def simple_fuel(x) do
floor(x / 3) - 2
end
end
First I take the input, map it to integers, calculate the fuel for each module, and then sum it up! To ensure my calculations are correct, I can make some tests given the sample information.
defmodule Aoc2019.Y2019.D1Test do
use ExUnit.Case
alias AdventOfCode.Y2019.D1
describe "simple_fuel/1" do
test "it computs the correct mass" do
assert 2 = D1.simple_fuel(12)
assert 2 = D1.simple_fuel(14)
assert 654 = D1.simple_fuel(1969)
assert 33583 = D1.simple_fuel(100_756)
end
end
end
Generally, these tests come with something small and testable to help ensure my code works.
Puzzle 2
Puzzle 2 simply expands on this by complicating the calculation of fuel. Now, the mass of the fuel is part of the equation. This is a great use case for recursion
def p2 do
input_stream()
|> Stream.map(&String.to_integer/1)
|> Stream.map(&accurate_fuel/1)
|> Enum.sum()
end
def accurate_fuel(x) when floor(x / 3) - 2 <= 0, do: 0
def accurate_fuel(x) do
fuel = floor(x / 3) - 2
fuel + accurate_fuel(fuel)
end
Again, testing the calculations quickly before hitting the GO button.
describe "accurate_fuel/1" do
test "it computes the correct mass " do
assert 2 = D1.accurate_fuel(14)
assert 966 = D1.accurate_fuel(1969)
assert 50346 = D1.accurate_fuel(100_756)
end
end
Final Version
2 stars in the bank, nice and quick! I can clean up the code a bit, the final version are below.
lib/Y2019/1.ex
:
import AdventOfCode
aoc 2019, 1 do
def p1, do: p(&simple_fuel/1)
def p2, do: p(&accurate_fuel/1)
def p(f) do
input_stream()
|> Stream.map(&String.to_integer/1)
|> Stream.map(f)
|> Enum.sum()
end
def simple_fuel(x) do
floor(x / 3) - 2
end
def accurate_fuel(x) do
fuel = floor(x / 3) - 2
case fuel do
f when f <= 0 -> 0
f -> f + accurate_fuel(f)
end
end
end
test/Y2019/D1Test.exs
:
defmodule Aoc2019.Y2019.D1Test do
use ExUnit.Case
alias AdventOfCode.Y2019.D1
describe "simple_fuel/1" do
test "it computs the correct mass" do
assert 2 = D1.simple_fuel(12)
assert 2 = D1.simple_fuel(14)
assert 654 = D1.simple_fuel(1969)
assert 33583 = D1.simple_fuel(100_756)
end
end
describe "accurate_fuel/1" do
test "it computes the correct mass " do
assert 2 = D1.accurate_fuel(14)
assert 966 = D1.accurate_fuel(1969)
assert 50346 = D1.accurate_fuel(100_756)
end
end
end
I decided to drop the pattern matching to only calculate fuel once, but it’s still readable.