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
Most Liked
adamu
I used:
-
Stream.cycle/1to handle the repeating horizontal values -
Enum.take_every/2to 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
I see I’m not the first one to find the Stream.cycle function 
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
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
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…)
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.







