Advent of Code 2021 - Day 1

This topic is about Day 1 of the Advent of Code 2021.

We have a private leaderboard (shared with users of Erlang Forums):

https://adventofcode.com/2021/leaderboard/private/view/370884

The entry code is:
370884-a6a71927

6 Likes

Here is my solution in Elixir:

And over at the Erlang Forums is my solution in Erlang:

3 Likes

Here’s mine:

advent_of_code/day_01.ex at master · code-shoily/advent_of_code (github.com)

Observations:

  • Though wasn’t applicable, but had a re-read of chunk_by and chunk_while-s document. Everytime something needs chunking, I reach out for chunk_by and end up using chunk or chunk_every
  • I had forgotten to use chunk_every's :discard
  • Livebook + Advent of Code = Elixir is the best way to solve AoC.
7 Likes

My solution using chunk_every/4

Part 1

#!/usr/bin/env elixir

File.stream!("input.txt")
|> Stream.map(&String.trim/1)
|> Stream.map(&String.to_integer/1)
|> Stream.chunk_every(2, 1, :discard)
|> Enum.count(fn [a, b] -> a < b end)
|> IO.inspect()

Part 2

#!/usr/bin/env elixir

File.stream!("input.txt")
|> Stream.map(&String.trim/1)
|> Stream.map(&String.to_integer/1)
|> Stream.chunk_every(3, 1, :discard)
|> Stream.map(&Enum.sum/1)
|> Stream.chunk_every(2, 1, :discard)
|> Enum.count(fn [a, b] -> a < b end)
|> IO.inspect()
7 Likes

omg … why did I not think about a < b and used b - a > 0 instead? Not just the first time but also afterwards when I was looking at it through F# :expressionless:

3 Likes

Actually, I did the same thing in Part 1, and realized that I can just write a < b in Part 2 :smiley:

1 Like

I took the questions quite literally in my head and on code. I was more obsessed with getting in the leaderboard so I can forgive myself for the first time. But I totally should have seen it the second time.

Also, glad to see your code again @Aetherus … I remember taking help from some of your solutions last year :slight_smile:

1 Like

Really? I’m flattered. I had a hard time solving problems in the later days of AoC, maybe I need to polish my programming skills more.

1 Like

I have been randomly solving Advent of Code problems throughout the year, with Elixir. But whenever I see a problem involving 2D arrays or dynamic programming, regardless of practice, I start to panic. One example that comes to mind is Year 2017, Day 3. The idea of solving that gets me nervous lol.

1 Like

TIL Enum.zip_reduce/3

  def parse(path) do
    File.stream!(path)
    |> Enum.map(&String.trim(&1))
    |> Enum.map(&String.to_integer(&1))
  end

  def depth_increment_count(input, step \\ 1) do
    Enum.zip_reduce([input, Enum.drop(input, step)], 0, fn [a, b], acc ->
      if b > a do
        acc + 1
      else
        acc
      end
    end)
  end

  def trios_increment(input) do
    depth_increment_count(input, 3)
  end

Edited for DRYing.

6 Likes

Exactly. I just worked out the answer to part 1. Part 2 is scary. I can’t find a non-brute-force way of solving it.

Yet another function in Enum I didn’t know :upside_down_face:

1 Like

In comparison of A1 + A2 + A3 and B1 + B2 + B3 you really only compare A1 and B3 b/c A2 == B1 and A3 == B2. I think that counts as “non brute force”.

6 Likes

Nice point. Based on your suggestion, I reimplemented part 2:

#!/usr/bin/env elixir

File.stream!("input.txt")
|> Stream.map(&String.trim/1)
|> Stream.map(&String.to_integer/1)
|> Stream.chunk_every(4, 1, :discard)  # <-- Now the window size is 4
|> Enum.count(fn [a, _, _, d] -> a < d end)  # <-- and just compare the first and last elements in each window
|> IO.inspect()

No sum at all.

5 Likes

Did not know about zip_with

1 Like

Hi again, great to see everyone for another year of AoC!

Haven’t been coding Elixir in a while so was a bit rusty but ended up with a similar solution. However I didn’t come to think about using chunk_every for the first chunking and instead did a l |> Enum.zip(Enum.drop(l, 1)), will try to internalise that :slight_smile:

  def run1(data) do
    parse_input(data)
    |> sum_increases()
  end

  def run2(data) do
    parse_input(data)
    |> Enum.chunk_every(3, 1, :discard)
    |> Enum.map(fn l -> Enum.sum(l) end)
    |> sum_increases()
  end

  defp parse_input(data) do
    data
    |> String.trim()
    |> String.split()
    |> Enum.map(&String.to_integer/1)
  end

  defp sum_increases(numbers) do
    numbers
    |> Enum.zip(Enum.drop(numbers, 1))
    |> Enum.map(fn {last, current} -> if current > last, do: :increased, else: :decreased end)
    |> Enum.filter(fn i -> i == :increased end)
    |> Enum.count()
  end
3 Likes

Unfortunately it looks like the leaderboard is now full :frowning_face:

Anyway, yet another solution using chunk_every:

defmodule Aoc2021.Day1 do
  def part1(input) do
    input
    |> parse()
    |> sliding_windows(2)
    |> Enum.count(fn [prev, curr] -> curr > prev end)
  end

  def part2(input) do
    input
    |> parse()
    |> sliding_windows(3)
    |> Enum.map(&Enum.sum/1)
    |> sliding_windows(2)
    |> Enum.count(fn [prev, curr] -> curr > prev end)
  end

  defp parse(input) do
    input
    |> String.split()
    |> Enum.map(&String.to_integer/1)
  end

  defp sliding_windows(enumerable, size), do: Enum.chunk_every(enumerable, size, 1, :discard)
end
1 Like

There’s a private leaderboard at the top of this topic. I don’t know if there’s a member limit on each private leaderboard.

1 Like

That private leaderboard has been used for several years and the limit of 200 users has been reached. I have posted the link and code for a new private leaderboard.

2 Likes

Just donated 5 dollars to AoC :upside_down_face: