Hello, coding maestros! Ukrainian Erlanger at your service , and it’s a thrilling Thursday. Today marks Day 14 of our exhilarating journey through Advent of Code, presenting a fresh puzzle for you to conquer. Dive into the challenge, flex those coding muscles, and, of course, share your ingenious solutions in the comments below. Let’s keep the coding camaraderie strong and turn this Thursday into a day of triumph! Happy coding, everyone!
3 Likes
I may have made that more complicated than it needed to be with the way I represented the grid. It was kind of slick for part 1 though.
2 Likes
For part 2 found cycle manually first, then implemented search for it
defmodule Aoc.Fourteen do
def parse(string) do
string
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.graphemes()
end)
|> load()
end
def load(data) do
for {line, y} <- Enum.with_index(data, 1), {i, x} <- Enum.with_index(line, 1), into: %{} do
{{y, x}, i}
end
end
def part_one(input) do
input
|> tilt()
end
def part_two(input) do
input
|> cycle(1_000_000_000)
end
defp tilt(map) do
{y_max, x_max} = maxs = map |> Map.keys() |> Enum.max()
for y <- 1..y_max, x <- 1..x_max do
{y, x}
end
|> Enum.reduce(filter_map(map), &tilt(&1, maxs, :north, &2))
|> north_weight(y_max)
end
defp filter_map(map) do
map |> Map.filter(&(elem(&1, 1) != "."))
end
defp tilt({y, x} = c, {y_max, x_max}, dir, acc) do
case Map.get(acc, c) do
"O" ->
new_acc = Map.delete(acc, c)
case dir do
:north -> roll_y(y..1, x, new_acc)
:south -> roll_y(y..y_max, x, new_acc)
:west -> roll_x(x..1, y, new_acc)
:east -> roll_x(x..x_max, y, new_acc)
end
_ ->
acc
end
end
def cycle(map, n) when is_integer(n) do
maxs = map |> Map.keys() |> Enum.max()
map = map |> filter_map()
1..n
|> Enum.reduce_while(
{map, %{}, %{}},
fn x, {acc, memo_i, memo_w} ->
case memo_i[acc] do
nil ->
new_acc = cycle(acc, maxs)
new_memo_i = Map.put(memo_i, acc, x)
new_memo_w = Map.put(memo_w, x, north_weight(acc, elem(maxs, 0)))
{:cont, {new_acc, new_memo_i, new_memo_w}}
previous ->
cycle_length = x - previous
index = rem(n - x, cycle_length) + 1
{:halt, memo_w[previous + index]}
end
end
)
end
def cycle(map, {y_max, x_max} = maxs) do
[
{:north, yx(1..y_max, 1..x_max)},
{:west, xy(1..x_max, 1..y_max)},
{:south, yx(y_max..1, x_max..1)},
{:east, xy(x_max..1, y_max..1)}
]
|> Enum.reduce(map, fn {dir, coords}, acc ->
Enum.reduce(coords, acc, &tilt(&1, maxs, dir, &2))
end)
end
defp roll_y(from..to//by = range, x, acc) do
Enum.reduce_while(range, acc, fn y, acc ->
case {y, Map.get(acc, {y, x})} do
{^to, nil} ->
{:halt, Map.put(acc, {y, x}, "O")}
{_, nil} ->
{:cont, acc}
_ ->
{:halt, Map.put(acc, {y - by, x}, "O")}
end
end)
end
defp roll_x(from..to//by = range, y, acc) do
Enum.reduce_while(from..to, acc, fn x, acc ->
case {x, Map.get(acc, {y, x})} do
{^to, nil} ->
{:halt, Map.put(acc, {y, x}, "O")}
{_, nil} ->
{:cont, acc}
_ ->
{:halt, Map.put(acc, {y, x - by}, "O")}
end
end)
end
def yx(y_range, x_range) do
for y <- y_range, x <- x_range do
{y, x}
end
end
def xy(x_range, y_range) do
for x <- x_range, y <- y_range do
{y, x}
end
end
def north_weight(map, y_max) do
map
|> Enum.map(&weight(&1, y_max))
|> Enum.sum()
end
defp weight({{y, x}, v}, len) do
case v do
"O" ->
len - y + 1
_ ->
0
end
end
end
input = File.read!("priv/14.txt") |> Aoc.Fourteen.parse()
input |> Aoc.Fourteen.part_one() |> IO.inspect(label: "part 1")
input |> Aoc.Fourteen.part_two() |> IO.inspect(label: "part 2")
1 Like