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 10 of 25 Posts 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…)
Aetherus

Aetherus OP

Me the same. I’m struggling with iterating through a range with a specific step.

Here’s my solution:

#!/usr/bin/env elixir

field = "./day3.txt"
        |> File.stream!([], :line)
        |> Enum.map(&String.trim/1)

width = IO.iodata_length(hd(field))
height = length(field)
field = field
        |> Stream.with_index()
        |> Stream.map(fn{row, i}->{i, row}end)
        |> Map.new()

get_trees = fn({right, down})->
  (0..height-1)
  |> Stream.chunk_every(down, down, :discard)
  |> Stream.map(&hd/1)
  |> Enum.reduce({0, {0, 0}}, fn(_, {trees, {i, j}})->
    row = field[i]
    trees = if :binary.at(row, j) == ?#, do: trees + 1, else: trees
    {trees, {i + down, rem(j + right, width)}}
  end)
  |> elem(0)
end

# Part 1
IO.puts get_trees.({3, 1})

# Part 2
[{1, 1}, {3, 1}, {5, 1}, {7, 1}, {1, 2}]
|> Enum.map(get_trees)
|> Enum.reduce(&*/2)
|> IO.inspect()
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
Aetherus

Aetherus OP

Love the idea of Stream.cycle with Enum.at.

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")
Aetherus

Aetherus OP

Stream.take_every/2! That’s what I’m looking for!

adamu

adamu

What’s the benefit of Stream.drop(shift) |> Enum.at(0) over just Enum.at(shift)?

LostKobrakai

LostKobrakai

This was a fun one. I build a map of %{{x :: non_neg_integer, y :: non_neg_integer} => type :: :tree | :space} from the input. For the horizontal repeating I simply used rem(x, max_x) to preprocess the coordinates before checking the map. For building the path through the map I used Stream.unfold to build a stream of types at the coordinates following the trajectory from the start.

https://github.com/LostKobrakai/aoc2020/blob/master/lib/aoc2020/day3.ex

kwando

kwando

One benefit is that you get to write one more line of lovely Elixir code :slight_smile:

I think it is better without that Stream.drop though, so I have removed tit from my final version on GitHub.

Aetherus

Aetherus OP

Interesting indeed. Instead of fold like mine and many other contenders’ code, you unfold. That’s a new angle of looking at the problem.

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