Advent of Code 2019 - Day 1

Really good use of doctests!

2 Likes

Thanks! If I had known about Stream.drop/1, my part2_with_stream_iteration function would have looked like @sasajuric 's solution.

2 Likes

My solution is eerily similar to a lot of the posts here:

I did go back and replace the tests with doctests. Should help keep things clear going forward. Great idea!

2 Likes

My solutions for Day 1

I wrote them in a way that I thought was easy for me to reason about. I havenā€™t seen the answers above yet (Iā€™m going to do that later tonight ā€” I always learn so much new that way :slight_smile: ). Snippets below:

Part 1

defmodule Part1 do
  @doc """
      iex> fuel_for_mass(12)
      2

      iex> fuel_for_mass(14)
      2

      iex> fuel_for_mass(1969)
      654

      iex> fuel_for_mass(100756)
      33583
  """
  def fuel_for_mass(mass) do
    div(mass, 3) - 2
  end

  def total_fuel(input_file) do
    File.stream!(input_file)
    |> Stream.map(&String.trim/1)
    |> Stream.map(&String.to_integer/1)
    |> Stream.map(&fuel_for_mass/1)
    |> Enum.sum()
  end
end

Part 2

defmodule Part2 do
  @doc """
      iex> fuel_for_mass(12)
      2

      iex> fuel_for_mass(14)
      2

      iex> fuel_for_mass(1969)
      654

      iex> fuel_for_mass(100756)
      33583
  """
  def fuel_for_mass(mass) do
    div(mass, 3) - 2
  end

  @doc """
      iex(9)> total_fuel_for_mass(14)
      2

      iex(10)> total_fuel_for_mass(1969)
      966

      iex(11)> total_fuel_for_mass(100756)
      50346
  """
  def total_fuel_for_mass(mass_or_fuel) do
    fuel = fuel_for_mass(mass_or_fuel)

    if fuel > 0 do
      fuel + total_fuel_for_mass(fuel)
    else
      0
    end
  end

  def total_fuel(input_file) do
    File.stream!(input_file)
    |> Stream.map(&String.trim/1)
    |> Stream.map(&String.to_integer/1)
    |> Stream.map(&total_fuel_for_mass/1)
    |> Enum.sum()
  end
end
1 Like

Iā€™m learning Elixir with doing AOC and got improved a lot. Thanks to this post, I borrowed a lot of brilliant ideas from @sasajuric @dimitarvp and improved my repo. :grin:

Hereā€™s the day1 solution I end up with:

defmodule AOC.Y2019.Day01 do

  @masses "2019/day01.txt"
          |> AOC.Input.stream(&String.to_integer/1)
          |> Enum.to_list()

  def part1 do
    @masses
    |> Enum.reduce(0, &(div(&1, 3) - 2 + &2))
  end

  def part2 do
    @masses
    |> Enum.reduce(0, &(fuel(&1) + &2))
  end

  def fuel(mass) do
    case div(mass, 3) - 2 do
      x when x > 0 ->
        x + fuel(x)

      _ ->
        0
    end
  end
end
2 Likes

Here is mine

defmodule AOC.Day1 do
  def part1(file_stream) do
    file_stream
    |> Enum.reduce(0, fn n, acc -> acc + calculate_fuel(n) end)
  end

  def part2(file_stream) do
    file_stream
    |> Enum.reduce(0, fn n, acc -> acc + additional_fuel(n, 0) end)
  end

  defp calculate_fuel(n), do: div(n, 3) - 2

  defp additional_fuel(fuel, additional) when fuel < 6, do: additional

  defp additional_fuel(fuel, additional) do
    new_fuel = calculate_fuel(fuel)
    additional_fuel(new_fuel, additional + new_fuel)
  end
end

And here is test. I create file stream in the test

defmodule Day1Test do
  use ExUnit.Case

  alias AOC.Day1

  test "solution day 1 part 1" do
    input = read_input("test/input/day1_input")
    assert Day1.part1(input) == 3_152_919
  end

  test "solution day 1 part 2" do
    input = read_input("test/input/day1_input")
    assert Day1.part2(input) == 4_726_527
  end

  defp read_input(file) do
    file
    |> File.stream!([], :line)
    |> Stream.map(fn line ->
      {integer, _leftover} = Integer.parse(line)
      integer
    end)
  end
end

Repo: https://github.com/gsarwate/advent_of_code_2019/blob/master/lib/aoc/day1.ex

2 Likes

and incorporating great suggestions in this thread, my ā€œfinalā€ day 1 looks like:

defmodule AOC.Day1 do

  def part1 do
    AOC.integer_stream(1)
    |> Enum.reduce(0, fn mass, acc -> fuel(mass) + acc end)
  end

  def part2 do
    AOC.integer_stream(1)
    |> Stream.map(&fuel/1)
    |> Enum.reduce(0, fn mass, acc -> add_fuel(mass) + acc end)
  end

  def fuel(mass) do
    max(0, trunc(mass / 3) - 2)
  end

  def add_fuel(mass) do
    case fuel(mass) do
      0 -> 0
      f -> mass + add_fuel(f)
    end
  end

end
1 Like

Iā€™ll be keeping my progress in https://github.com/sb8244/advent-of-code-2019

Day One

2 Likes

Hereā€™s mine:

1 Like

Thatā€™s a great idea. Does the site let you start late or do you have to keep up every day?

Are you going to do some videos like last year? :smiley:

Yep, you can solve the tasks whenever youā€™d like, esp. if you donā€™t care about your place in the leaderboard :slight_smile:

2 Likes

Hereā€™s mine solution: https://github.com/pozhega/AoC/blob/master/lib/aoc/Y2019/d1.ex

I decided to record my Erlang solutions this year, to show how much I can fail in trying to find a decently effective solution and how I come up with code.

Hereā€™s Day 1:

7 Likes