bjorng
Most Liked
igorb
Solution using dynamic programming (prefix sums): https://github.com/ibarakaiev/advent-of-code-2023/blob/main/lib/advent_of_code/day_11.ex. There are some possible optimizations like recording coordinates at the same time as the vertical prefix sum, but it would take away from readability ![]()
lud
To expand I sort the empty Y coords descending, and for each one I bump each XY in the galaxy list. Same for X.
I have an idea to do it all at once but I’m not chasing milliseconds today ![]()
midouest
This one seemed like a great opportunity to learn a bit of Nx. I took the naive approach for part 1 and duplicated all of the rows and columns. Obviously that didn’t work out in part 2 ![]()
Part 1
sky =
for line <- String.split(input, "\n", trim: true) do
for char <- String.graphemes(line) do
if char == "#", do: 1, else: 0
end
end
sky_tensor = Nx.tensor(sky, type: :u8, names: [:y, :x])
empty_ys = Nx.any(sky_tensor, axes: [:x]) |> Nx.logical_not() |> Nx.to_list()
empty_xs = Nx.any(sky_tensor, axes: [:y]) |> Nx.logical_not() |> Nx.to_list()
pad_ys =
empty_ys
|> Enum.with_index()
|> Enum.flat_map(fn {empty, index} -> List.duplicate(index, empty + 1) end)
|> Nx.tensor(type: :u8)
pad_xs =
empty_xs
|> Enum.with_index()
|> Enum.flat_map(fn {empty, index} -> List.duplicate(index, empty + 1) end)
|> Nx.tensor(type: :u8)
big_sky =
sky_tensor
|> Nx.take(pad_ys, axis: :y)
|> Nx.take(pad_xs, axis: :x)
galaxies =
for {line, y} <- big_sky |> Nx.to_list() |> Enum.with_index(),
{galaxy, x} <- Enum.with_index(line),
reduce: [] do
acc -> if galaxy == 1, do: [{y, x} | acc], else: acc
end
pairs =
for {{y1, x1}, i} <- Enum.with_index(galaxies),
{y2, x2} <- Enum.drop(galaxies, i + 1) do
[[y1, x1], [y2, x2]]
end
|> Nx.tensor(type: :s64)
Nx.abs(Nx.subtract(pairs[[.., 0, 0]], pairs[[.., 1, 0]]))
|> Nx.add(Nx.abs(Nx.subtract(pairs[[.., 0, 1]], pairs[[.., 1, 1]])))
|> Nx.sum()
Part 2
galaxies =
for {line, y} <- sky |> Enum.with_index(),
{galaxy, x} <- Enum.with_index(line),
reduce: [] do
acc -> if galaxy == 1, do: [{y, x} | acc], else: acc
end
y_indexes =
empty_ys
|> Enum.with_index()
|> Enum.flat_map(fn
{1, i} -> [i]
_ -> []
end)
x_indexes =
empty_xs
|> Enum.with_index()
|> Enum.flat_map(fn
{1, i} -> [i]
_ -> []
end)
galaxies =
for {y, x} <- galaxies do
sy = Enum.count(y_indexes, &(&1 < y))
sx = Enum.count(x_indexes, &(&1 < x))
{y + 999_999 * sy, x + 999_999 * sx}
end
pairs =
for {{y1, x1}, i} <- Enum.with_index(galaxies),
{y2, x2} <- Enum.drop(galaxies, i + 1) do
[[y1, x1], [y2, x2]]
end
|> Nx.tensor(type: :s64)
Nx.abs(Nx.subtract(pairs[[.., 0, 0]], pairs[[.., 1, 0]]))
|> Nx.add(Nx.abs(Nx.subtract(pairs[[.., 0, 1]], pairs[[.., 1, 1]])))
|> Nx.sum()
woojiahao
Added quite a few new helper functions to speed up writing AOC solutions, notably:
load_day_as_gridto automatically parse input as a map of coordinates to pointsdistinct_pairsto generate all distinct pairs of elements within a listlist_set_differenceto calculate the set difference between 2 lists (reducing the need forMapSet.newcalls)
Aetherus
I only expanded the universe once for each part of the puzzle. Dividing by two is because for each pair of the galaxies a and b, I calculated the distance between a and b and the distance between b and a. I know I could calculate the distances only once. I just didn’t bother to do that optimization.







