bjorng
Erlang Core Team
Advent of Code 2024 - Day 2
Here is my solution for day 2 of Advent of Code:
https://github.com/bjorng/advent-of-code/blob/main/2024/day02/lib/day02.ex
Most Liked
sevenseacat
Author of Ash Framework
dimitarvp
Life sadly kept getting in the way but ultimately:
defmodule Day02 do
@moduledoc ~S"""
A solution to https://adventofcode.com/2024/day/2.
"""
@type level :: pos_integer()
@type distance :: integer()
@type report :: [level()]
@spec all_variants_with_one_element_removed(report()) :: [report()]
def all_variants_with_one_element_removed(list) do
for i <- 0..(length(list) - 1), do: list |> List.delete_at(i)
end
@spec sign(integer()) :: :zero | :minus | :plus
def sign(0), do: :zero
def sign(i) when i > 0, do: :plus
def sign(i) when i < 0, do: :minus
@spec distances(report()) :: [distance()]
def distances([first | rest]) do
rest
|> Enum.reduce({first, []}, fn current_level, {previous_level, distances} ->
{current_level, [current_level - previous_level | distances]}
end)
|> then(fn {_last_level, distances} -> Enum.reverse(distances) end)
end
@spec same_signs?([distance()]) :: boolean()
def same_signs?(list) do
list
|> Enum.map(&sign/1)
|> Enum.uniq()
|> length()
|> Kernel.==(1)
end
@spec safe?(report()) :: boolean()
def safe?(report) do
distances = distances(report)
monotonical? = same_signs?(distances)
safely_advancing? =
distances |> Enum.map(&abs/1) |> Enum.all?(fn distance -> distance <= 3 end)
monotonical? and safely_advancing?
end
@spec safe_with_a_dampener?(report()) :: boolean()
def safe_with_a_dampener?(report) do
safe?(report) or
report |> all_variants_with_one_element_removed() |> Enum.any?(&safe?/1)
end
@doc ~S"""
iex> Day02.part_1("7 6 4 2 1\n1 2 7 8 9\n9 7 6 2 1\n1 3 2 4 5\n8 6 4 4 1\n1 3 6 7 9\n")
nil
"""
@spec part_1(String.t()) :: non_neg_integer()
def part_1(input \\ Aoc.input(2)) do
input
|> Aoc.parse_lines_of_integers()
|> Enum.count(&safe?/1)
end
@spec part_2(String.t()) :: non_neg_integer()
def part_2(input \\ Aoc.input(2)) do
input
|> Aoc.parse_lines_of_integers()
|> Enum.count(&safe_with_a_dampener?/1)
end
end
Did my best to make it readable and intuitive, even benchmarked three competing implementation I had ideas about, and only posted the one that won.
3
lud
No optimization here, just building all possible list before trying them one by one ![]()
defmodule AdventOfCode.Solutions.Y24.Day02 do
alias AoC.Input
def parse(input, _part) do
Enum.map(Input.stream!(input, trim: true), &parse_line/1)
end
defp parse_line(line) do
Enum.map(String.split(line, " "), &String.to_integer/1)
end
def part_one(problem) do
problem
|> Enum.filter(&safe?/1)
|> length()
end
defp safe?([a, b | _] = list) when a < b, do: safe?(:asc, list)
defp safe?([a, b | _] = list) when a > b, do: safe?(:desc, list)
defp safe?([a, a | _]), do: false
defp safe?(:asc, [a, b | rest]) when abs(a - b) in 1..3 and a < b, do: safe?(:asc, [b | rest])
defp safe?(:desc, [a, b | rest]) when abs(a - b) in 1..3 and a > b, do: safe?(:desc, [b | rest])
defp safe?(_, [_last]), do: true
defp safe?(_, _), do: false
def part_two(problem) do
problem
|> Enum.filter(&safeish?/1)
|> length()
end
defp safeish?(list) do
candidates = [list | Enum.map(0..(length(list) - 1), &List.delete_at(list, &1))]
Enum.any?(candidates, &safe?/1)
end
end
Edit:
candidates = Stream.concat([list], Stream.map(0..(length(list) - 1), &List.delete_at(list, &1)))
This would save memory but given the input size it’s actually slower.
2
Trending in Challenges
Well some of us wanted a difficulty spike - and today we got one :sweat_smile:
https://github.com/sevenseacat/advent_of_code/blob/main/l...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
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
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
Squid Mesh is an open source workflow automation runtime for Elixir applications.
It is aimed at Phoenix and OTP apps that want to defin...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #elixirconf-us
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









