Aetherus

Aetherus

Advent of Code 2020 - Day 3

This topic is about Day 3 of the Advent of Code 2020 .

Thanks to @egze, we have a private leaderboard:
https://adventofcode.com/2020/leaderboard/private/view/39276

The join code is:
39276-eeb74f9a

First Post! Switch mode

aaronnamba

aaronnamba

Might not be the most efficient solution, but fairly straightforward:

Day 3 Notes

  • Took a bit longer than it should to build the data structure, then got hung up for several minutes on a row vs. col mixup when accessing it (forgot that I need to get_in(map, [y, x]) instead of [x, y]).
  • Still pretty straightforward, my initial solution worked as expected for both parts (once I got it implemented properly). Part 2 did not add a new twist this time, which was unusual. (Unless of course, you assumed that you would always move down by one…)

Most Liked

adamu

adamu

I used:

  • Stream.cycle/1 to handle the repeating horizontal values
  • Enum.take_every/2 to handle skipping the downward slope.
  • The input wasn’t very long, so I just brute forced the horizontal value with Enum.at/2.
  def slope(v_x, v_y) do
    {_, trees} =
      File.read!("input")
      |> String.trim()
      |> String.split("\n")
      |> Enum.take_every(v_y)
      |> Enum.map(&String.to_charlist/1)
      |> Enum.reduce({0, 0}, fn row, {x, trees} ->
        trees =
          case Stream.cycle(row) |> Enum.at(x) do
            ?# -> trees + 1
            ?. -> trees
          end

        {x + v_x, trees}
      end)

    trees
  end
kwando

kwando

I see I’m not the first one to find the Stream.cycle function :slight_smile:
My version:

defmodule Aoc2020.Day03 do
  def part1(input) do
    count_trees(input, {3, 1})
  end

  def part2(input) do
    slopes = [
      {1, 1},
      {3, 1},
      {5, 1},
      {7, 1},
      {1, 2}
    ]

    for slope <- slopes, reduce: 1 do
      product -> product * count_trees(input, slope)
    end
  end

  def count_trees(input, {dx, dy}) do
    input
    |> Stream.take_every(dy)
    |> Stream.map(&Stream.cycle/1)
    |> Enum.reduce({0, 0}, fn
      row, {trees, shift} ->
        row
        |> Stream.drop(shift)
        |> Enum.at(0)
        |> case do
          ?. ->
            {trees, shift + dx}

          ?# ->
            {trees + 1, shift + dx}
        end
    end)
    |> elem(0)
  end

  def input_stream(path) do
    File.stream!(path)
    |> Stream.map(&parse/1)
  end

  defp parse(line) do
    line
    |> String.trim()
    |> String.to_charlist()
  end
end

input = Aoc2020.Day03.input_stream("input.txt")

input
|> Aoc2020.Day03.part1()
|> IO.inspect(label: "part1")

input
|> Aoc2020.Day03.part2()
|> IO.inspect(label: "part2")
Damirados

Damirados

My solution with streams keeping only 1 line of map in memory at any given time.

defmodule Event3 do
  def run do
    part1_ruleset = [{3, 1}]
    part2_ruleset = [{1, 1}, {3, 1}, {5, 1}, {7, 1}, {1, 2}]
    IO.puts("Test part1: #{solver("input/event3/test.txt", part1_ruleset)}")
    IO.puts("Puzzle part1: #{solver("input/event3/puzzle.txt", part1_ruleset)}")
    IO.puts("Test part2: #{solver("input/event3/test.txt", part2_ruleset)}")
    IO.puts("Puzzle part2: #{solver("input/event3/puzzle.txt", part2_ruleset)}")
  end

  def solver(path, ruleset) do
    accs = Enum.map(ruleset, &rule_to_acc/1)

    input_stream(path)
    |> Stream.drop(1)
    |> Stream.transform(accs, &step_all/2)
    |> Stream.take(-length(ruleset))
    |> Stream.flat_map(& &1)
    |> Enum.reduce(&(&1 * &2))
  end

  def input_stream(path), do: path |> File.stream!() |> Stream.map(&parse_input/1)

  def parse_input(input), do: String.trim(input) |> String.graphemes() |> Enum.map(&(&1 == "#"))

  def step_all(input, acc), do: Enum.map(acc, &step(input, &1)) |> Enum.unzip()

  def step(input, {count, index, step, step_down, step_down}) do
    width = length(input)
    count = count + ((Enum.at(input, index) && 1) || 0)
    {[count], {count, rem(index + step, width), step, step_down, 1}}
  end

  def step(_input, {count, index, step, step_down, down_counter}),
    do: {[count], {count, index, step, step_down, down_counter + 1}}

  def rule_to_acc({right, down}), do: {0, right, right, down, 1}
end

Last Post!

APB9785

APB9785

Creator of ECSx

Part 1: Basic modulo wrap

Part 2: In the Functional style:

part_2 =
  Enum.reduce([1, 3, 5, 7], 1, &(&2 * travel(input, &1)))
  |> (fn x -> x * travel2(input) end).() 

where ‘travel’ traverses the map with slope -1 / n, and ‘travel2’ uses slope -2.

Full solution @ Github

Where Next?

Trending in Challenges Top

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New

We're in Beta

About us Mission Statement