Day11
Mix.install([
{:kino_aoc, git: "https://github.com/ljgago/kino_aoc"},
{:benchee, "~> 1.0"},
{:nimble_parsec, "~> 1.0"},
{:libgraph, "~> 0.16.0"},
{:math, "~> 0.7.0"}
])
Get Input
{:ok, data} = KinoAOC.download_puzzle("2023", "11", System.fetch_env!("LB_AOC_SECRET"))
Solve
defmodule Day11 do
@dots MapSet.new(["."])
def out(res, t), do: IO.puts("Res #{t}: #{res}")
def run(data, part_dist) do
data
|> String.split("\n", trim: true)
|> parse()
|> expand(part_dist)
|> get_galaxies()
|> permutations()
|> paths()
|> Enum.sum()
end
def parse(rows) do
Enum.map(rows, &String.split(&1, "", trim: true))
end
def expand(data, dist) do
{data, rows} = get_expand_coords(data, dist)
{data, cols} = data |> transpose() |> get_expand_coords(dist)
{transpose(data), {rows, cols}}
end
def transpose(data) do
data |> Enum.zip() |> Enum.map(&Tuple.to_list/1)
end
def get_expand_coords(rows, dist) do
rows
|> Enum.reduce({0, []}, fn row, {ind, acc} ->
delta = (MapSet.new(row) == @dots && dist) || 1
{ind + delta, [{row, ind + delta} | acc]}
end)
# taking data from {_tmp_ind, data}
|> elem(1)
|> Enum.reduce({[], []}, fn {row, ind}, {data, ind_acc} ->
{[row | data], [ind | ind_acc]}
end)
end
def get_galaxies({data, {rows, cols}}) do
data
|> Enum.with_index()
|> Enum.flat_map(fn {row, r} ->
row
|> Enum.with_index()
|> Enum.reduce([], fn elem, acc ->
case elem do
{"#", c} ->
[{Enum.at(rows, r), Enum.at(cols, c)} | acc]
_ ->
acc
end
end)
end)
end
def permutations(galaxies) do
for a <- galaxies, b <- galaxies, a != b, into: MapSet.new(), do: MapSet.new([a, b])
end
def paths(set) do
set
|> Enum.to_list()
|> Enum.map(&Enum.to_list/1)
|> Enum.map(&manhattan_dist/1)
end
def manhattan_dist([{ra, ca}, {rb, cb}]) do
abs(ra - rb) + abs(ca - cb)
end
end
Check
ExUnit.start(autorun: false)
defmodule Day11.Test do
use ExUnit.Case, async: false
@td1 """
...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....
"""
setup do
{:ok, data} = KinoAOC.download_puzzle("2023", "11", System.fetch_env!("LB_AOC_SECRET"))
%{data: data}
end
test "solves test cases" do
assert Day11.run(@td1, 2) == 374
assert Day11.run(@td1, 10) == 1030
assert Day11.run(@td1, 100) == 8410
end
test "solves live cases", %{data: data} do
assert Day11.run(data, 2) == 9_609_130
assert Day11.run(data, 1_000_000) == 702_152_204_842
end
end
ExUnit.run()
data |> Day11.run(2) |> Day11.out("t1")
data |> Day11.run(1_000_000) |> Day11.out("t2")