# Advent of Code 2021 - Day 1

Hmm, my non-optimal solution. First one here to use Enum.with_index . Probably not a good sign!

`````` def parse_input(input) do
input
|> Enum.map(fn x -> String.to_integer(x) end)
|> IO.inspect
end

def find_increased_number_count(numbers) do
Enum.reduce(numbers, {:infinity, 0}, fn x, {prev, count} ->
case x > prev do
true ->  {x, count + 1}
false -> {x, count}
end
end)
end

def creaete_sliding_windows(numbers) do
Enum.with_index(numbers)
|> Enum.map(fn {number, index} -> number + Enum.at(numbers, index + 1, 0) + Enum.at(numbers, index + 2, 0) end)
|> IO.inspect
end
``````
1 Like

Hereās my take:

``````defmodule Sol do
@file_path Path.join(~w(priv input.txt))

def run_1(file \\ @file_path) do
file
|> prepare_stream()
|> count(&increase?/2)
end

def run_2(file \\ @file_path) do
file
|> prepare_stream()
|> to_sliding_window()
|> Stream.map(&sum_window/1)
|> count(&increase?/2)
end

defp prepare_stream(file) do
file
|> File.stream!()
|> Stream.map(&String.trim/1)
|> Stream.map(&String.to_integer/1)
end

defp to_sliding_window(stream, size \\ 3) do
end

defp sum_window(numbers) when length(numbers) == 3, do: Enum.sum(numbers)

defp count(stream, condition) do
{_, count} =
Enum.reduce(stream, {nil, 0}, fn val, {prev, count} ->
count =
case condition.(prev, val) do
true -> count + 1
false -> count
end

{val, count}
end)

count
end

defp increase?(prev, curr)
when is_integer(prev) and
is_integer(curr) and
prev < curr do
true
end

defp increase?(_, _), do: false
end
``````
2 Likes

A no-brainer optimization is to convert a `[{elem, index}]` list into a map `%{index => elem}`.

``````list
|> Enum.with_index()
|> Map.new(fn {elem, index} -> {index, elem} end)
``````

Accessing a list element by index is O(index), while accessing a value by key in a map is O(log n) I guess.

2 Likes

My solution is using pattern matching and recursion. I could also reuse `part1` for `part2` by preprocessing the input.

The input is small enough so I didnāt bother with streaming.

``````defmodule Day1 do
def part1([x | [y | _] = rest]) when y > x, do: 1 + part1(rest)
def part1([_ | rest]), do: part1(rest)
def part1([]), do: 0

def part2(input) do
input
|> avg3()
|> part1()
end

defp avg3([a | [b | [c | _]] = rest]),
do: [a + b + c | acc_avg(rest)]

defp avg3(_), do: []

def parse_file(path) do
path
|> Path.expand(__DIR__)
|> parse_input()
end

def parse_input(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&String.to_integer/1)
end
end

"example.txt"
|> Day1.parse_file()
|> Day1.part1()
``````
2 Likes

Very interesting solution. Iād love to see a tail-recursive version

By the way, `[a | [b | [c | _]]]` can be written as `[a, b, c | _]`.

1 Like

It is LiveBook, so I paste it as a whole:

## Day 1

``````stream =
File.stream!("day1.txt")
|> Stream.map(&String.to_integer(String.trim(&1)))
``````

Compute count of consecutive increases

``````stream
|> Enum.count(fn [a, b] -> a < b end)
``````

Compute count of consecutive increases of sums of trigrams

``````stream
|> Stream.chunk_every(3, 1)
|> Stream.map(&Enum.sum/1)
|> Enum.count(fn [a, b] -> a < b end)
``````
4 Likes

First time poster, first time playing with Livebook. Itās actually pretty great for this!

posting the export, so you can re-import

``````
# Day 1

## Input

<!-- livebook:{"livebook_object":"cell_input","name":"input","type":"text","value":"199 200 208 210 200 207 240 269 260 263"} -->

## Part 1

```elixir
processed = IO.gets(:input) |> String.split(~r{\s}, trim: true) |> Enum.map(&String.to_integer/1)
```

```elixir
processed
|> Enum.map(fn [x, y] -> y > x end)
|> Enum.count(& &1)
```

## Part 2

```elixir
processed = IO.gets(:input) |> String.split(~r{\s}, trim: true) |> Enum.map(&String.to_integer/1)
```

```elixir
processed
|> Enum.map(&Enum.sum/1)
|> Enum.map(fn [x, y] -> y > x end)
|> Enum.count(& &1)
```

``````

EDIT: Why did I brainfart and didnāt put fun directly into count

1 Like

Iām aware, but I wanted to match the `rest` part so I can continue recursing (could have done that like `part([b, c | rest])` though.

I usually lean on this statement regarding body vs tail recursion.
https://www.erlang.org/doc/efficiency_guide/myths.html#myth--tail-recursive-functions-are-much-faster-----than-recursive-functions

1 Like

My take on it: y2021/d1.ex

This is such a simple problem yet I learned quite a bit looking at everyoneās solutions here. Thank you for sharing everyone.

I hope to see more like these in the next one!

5 Likes

That is an awesome observation!

3 Likes

Me too.

By the way, hereās my AoC-2017 Day 3 Part 2 solution, though I worked out today, and far from optimal

``````#!/usr/bin/env elixir

input = 265149  # my input number

step = fn
{n, {n, y}} when y == -n -> {n + 1, {n + 1, y}}  # bottom-right
{n, {x, y}} when y == -n -> {n, {x + 1, y}}  # towards bottom-right
{n, {n, n}} -> {n, {n - 1, n}}  # top-right
{n, {n, y}} -> {n, {n, y + 1}}  # towards top-right
{n, {x, n}} when x == -n -> {n, {x, n - 1}}  # top-left
{n, {x, n}} -> {n, {x - 1, n}}  # towards top-left
{n, {x, y}} when x == -n and y == -n -> {n, {x + 1, y}}  # bottom-left
{n, {x, y}} when x == -n -> {n, {x, y - 1}}  # towards bottom-left
end

{%{{0, 0} => 1}, {1, {1, 0}}}
|> Stream.unfold(fn {map, {_, {x, y}} = s} ->
sum = for i <- -1..1, j <- -1..1, reduce: 0 do
sum -> sum + Map.get(map, {x + i, y + j}, 0)
end
map = Map.put(map, {x, y}, sum)
{map, {map, step.(s)}}
end)
|> Stream.map(&Enum.max(Map.values(&1)))
|> Stream.drop_while(& &1 <= input)
|> Enum.at(0)
|> IO.inspect()
``````
1 Like

Nice! I played a golf match this morning, pinning my F# code versus my Elixir code. Looks like that will be this years AoC theme for me

Enum.reduce for part 1, manual reduce for part 2. Did this in five minutes at 11pm, will probably optimize the solution more eventually.

My solution:

``````defmodule Day01 do
@sample ~w/199
200
208
210
200
207
240
269
260
263/
|> Enum.map(&String.to_integer/1)

@report_list "assets/report_measurement.txt"
|> String.split(~r/\n/, trim: true)
|> Enum.map(&String.to_integer/1)

def list do
@report_list
end

defp larger_than_previous([]), do: []
defp larger_than_previous([h1 | [h2 | _] = t]) do
[h2 > h1 | larger_than_previous(t)]
end
defp larger_than_previous([_ | t]), do: larger_than_previous(t)

def count do
ltp_count(list())
end

def count_sample do
ltp_count(@sample)
end

# Puzzle 2

defp sum3([]), do: []
defp sum3([h1 | [h2 | [h3 | _]] = t]) do
[h1 + h2 + h3 | sum3(t)]
end
defp sum3([_ | t]), do: sum3(t)

def count2_sample do
sum3 = sum3(@sample)
ltp_count(sum3)
end

def count2 do
sum3 = sum3(@report_list)
ltp_count(sum3)
end

defp ltp_count(list) do
list_ltp = larger_than_previous(list)
Enum.count(list_ltp , fn x -> x == true end)
end
end

# Results of the Sample
IO.puts "The result of the 1st sample is: #{Day01.count_sample}"
IO.puts "The result of the 2nd sample is: #{Day01.count2_sample}"

# Results of the Puzzle
IO.puts "The result of the 1st puzzle is: #{Day01.count}"
IO.puts "The result of the 2nd puzzle is: #{Day01.count2}"
``````

run ` iex -S mix`:

``````iex(1)> r Day01
The result of the 1st sample is: 7
The result of the 2nd sample is: 5
The result of the 1st puzzle is: 1462
The result of the 2nd puzzle is: 1497
``````
1 Like

Hereās my humble - and not efficient - attempt:

``````defmodule Measurements do
def increases(depths, window_size \\ 1) do
depths
|> Enum.map(&Enum.sum/1)
|> Enum.count(fn [m1, m2] -> m2 > m1 end)
end
end
``````

(Assuming `depths` is a list of integers)

Itās a general solution that works with both parts, you just have to change the `window_size` from `1` to `3`.

5 Likes

I decided to avoid use Enum module just to play with the functions with different arity:

``````defmodule AofC2021.Day1 do
@day_1_input "2021/day1.txt"

def solve_first_part(input) do
do_first_solution(input)
end

def solve_first_part do
input = get_input()
do_first_solution(input)
end

def do_first_solution(input) do
input
|> parse_to_integers()
|> compare_with_previous_one()
|> count_increases()
end

defp parse_to_integers(input_list) do
Enum.map(input_list, &String.to_integer/1)
end

defp compare_with_previous_one(input_parsed) do
[first | [second | tail]] = input_parsed
get_comparisions(first, second, [second | tail], [])
end

defp get_comparisions(first, second, [_last], counters) when first > second do
counters ++ [:decreased]
end

defp get_comparisions(first, second, [_last], counters) when first < second do
counters ++ [:increased]
end

defp get_comparisions(first, second, tail, counters) when first == second do
counters = counters ++ [:nochange]
[first | [second | tail]] = tail
get_comparisions(first, second, [second | tail], counters)
end

defp get_comparisions(first, second, tail, counters) when first > second do
counters = counters ++ [:decreased]
[first | [second | tail]] = tail
get_comparisions(first, second, [second | tail], counters)
end

defp get_comparisions(first, second, tail, counters) when first < second do
counters = counters ++ [:increased]
[first | [second | tail]] = tail
get_comparisions(first, second, [second | tail], counters)
end

defp count_increases(counters) do
Enum.count(counters, fn i -> i == :increased end)
end

############### Second Part

def solve_second_part(input) do
do_second_solution(input)
end

def solve_second_part() do
input = get_input()
do_second_solution(input)
end

def do_second_solution(input) do
input
|> parse_to_integers()
|> get_sums_list()
|> compare_with_previous_one()
|> count_increases()
end

def get_sums_list(input) do
build_sum_list(input, [])
end

def build_sum_list([_first, _second], sums_list) do
sums_list
end

def build_sum_list([first|[second|[third|tail]]], sums_list) do
sum = first + second + third
sums_list = sums_list ++ [sum]
build_sum_list([second|[third|tail]], sums_list)
end

def get_input() do
end
end

``````
1 Like

My attempt as an Elixir beginner:

Part 1:

``````defmodule Submarine do
end

def depth_count([head | tail], previous, total) do
:true -> depth_count(tail, head, total + 1)
end
end

def depth_count([], _, total), do: total
end
``````

Part 2:

``````defmodule Submarine2 do
def depth_count(list) do
depth_count(list, Enum.take(list, 3), 0)
end

def depth_count([_head | tail], previous_window, total) do
sliding_window = Enum.take(tail, 3)
case Enum.count(sliding_window) == 3 do
:true ->
sliding_window_sum = Enum.reduce(sliding_window, fn x, acc -> x + acc end)
previous_window_sum = Enum.reduce(previous_window, fn x, acc -> x + acc end)
case sliding_window_sum > previous_window_sum do
:true -> depth_count(tail, sliding_window, total + 1)
:false -> depth_count(tail, sliding_window, total)
end
:false -> total
end
end
end
``````

Here is my take using recursion:

``````defmodule AoC2021.Day1 do
end

defp do_count_increases(_last, [], acc), do: acc

defp do_count_increases(last, [reading | rest], acc) do
new_acc = if reading > last, do: acc + 1, else: acc
end

def sliding_count_increases(_readings = [a, b, c | rest]) do
do_sliding_count_increases(a, b, c, rest, 0)
end

defp do_sliding_count_increases(_a, _b, _c, [], acc), do: acc

defp do_sliding_count_increases(a, b, c, [d | rest], acc) do
new_acc = if d > a, do: acc + 1, else: acc
do_sliding_count_increases(b, c, d, rest, new_acc)
end