add day 9 and 11

This commit is contained in:
Pim Kunis 2023-12-11 15:04:33 +01:00
parent 71cca82ce0
commit 0e7d2d7c6d
7 changed files with 492 additions and 32 deletions
23/elixir/lib/days

View file

@ -0,0 +1,74 @@
defmodule AOC.Day11 do
use AOC.Day, day: 11
def parse_input(lines) do
Enum.map(lines, &String.to_charlist/1)
end
def part1(image), do: calculate_distance_sum(image, 2)
def part2(image), do: calculate_distance_sum(image, 1_000_000)
def calculate_distance_sum(image, scaler) do
empty_space = find_empty_space(image)
find_galaxy_positions(image)
|> expand_galaxy_positions(empty_space, scaler)
|> calculate_shortest_paths()
|> Enum.sum()
end
def find_empty_space(image) do
empty_rows = find_empty_rows(image)
empty_columns =
image
|> List.zip()
|> Enum.map(&Tuple.to_list/1)
|> find_empty_rows()
{empty_rows, empty_columns}
end
def find_empty_rows(image) do
image
|> Enum.with_index()
|> Enum.filter(fn {row, _} -> Enum.all?(row, &(&1 == ?.)) end)
|> Enum.map(&elem(&1, 1))
end
def find_galaxy_positions(image) do
image
|> Enum.map(fn row ->
row
|> Enum.with_index()
|> Enum.filter(fn {space, _} -> space == ?# end)
|> Enum.map(&elem(&1, 1))
end)
|> Enum.with_index()
|> Enum.flat_map(fn {xs, y} ->
Enum.map(xs, &{y, &1})
end)
end
def expand_galaxy_positions(galaxy_positions, {empty_rows, empty_columns}, scaler) do
Enum.map(galaxy_positions, fn {y, x} ->
shift_y = Enum.count(empty_rows, &(&1 < y))
shift_x = Enum.count(empty_columns, &(&1 < x))
{y + shift_y * (scaler - 1), x + shift_x * (scaler - 1)}
end)
end
def calculate_shortest_paths(galaxy_positions) do
for g1 <- galaxy_positions, g2 <- galaxy_positions do
[g1, g2]
end
|> Enum.reject(fn [g1, g2] -> g1 == g2 end)
|> Enum.map(&Enum.sort/1)
|> Enum.uniq()
|> Enum.map(fn [{y1, x1}, {y2, x2}] ->
abs(y1 - y2) + abs(x1 - x2)
end)
end
end

View file

@ -1,7 +1,4 @@
defmodule AOC.Day8 do
# use AOC.Day, day: 8, input: "example1"
# use AOC.Day, day: 8, input: "example2"
# use AOC.Day, day: 8, input: "example3"
use AOC.Day, day: 8
@start "AAA"
@ -25,6 +22,20 @@ defmodule AOC.Day8 do
{instructions, nodes}
end
def part1({instructions, nodes}) do
reach_end(instructions, nodes)
end
def part2({instructions, nodes}) do
IO.puts("Use LCM calculator for the following numbers :)")
Enum.filter(nodes, fn {k, _v} -> String.ends_with?(k, "A") end)
|> Enum.map(fn {k, _v} -> find_cycle(instructions, nodes, k) end)
|> Enum.map(&elem(&1, 0))
|> Enum.map(&Integer.to_string/1)
|> Enum.join(" ")
end
def reach_end(instructions, nodes) do
Enum.reduce_while(instructions, {@start, 0}, fn instruction, {current_node, step_count} ->
if current_node == @stop do
@ -43,10 +54,6 @@ defmodule AOC.Day8 do
end)
end
def part1({instructions, nodes}) do
reach_end(instructions, nodes)
end
def find_cycle(instructions, nodes, start) do
Enum.reduce_while(instructions, {start, 0, nil}, fn instruction,
{current_node, step_count, last_end_count} ->
@ -68,29 +75,4 @@ defmodule AOC.Day8 do
end
end)
end
def brute_force_find_cycle(cycles) do
Stream.repeatedly(fn -> nil end)
|> Enum.reduce_while(cycles, fn _, cycles ->
all_ended = cycles |> Enum.map(&elem(&1, 0)) |> Enum.uniq() |> length() == 1
if all_ended do
{:halt, cycles |> hd() |> elem(0)}
else
[{count, cycle_count} | tl] = Enum.sort(cycles)
IO.inspect(count)
{:cont, [{count + cycle_count, cycle_count} | tl]}
end
end)
end
def part2({instructions, nodes}) do
IO.puts("Use LCM for the following numbers :)")
Enum.filter(nodes, fn {k, _v} -> String.ends_with?(k, "A") end)
|> Enum.map(fn {k, _v} -> find_cycle(instructions, nodes, k) end)
|> Enum.map(&elem(&1, 0))
|> Enum.map(&Integer.to_string/1)
|> Enum.join(" ")
end
end

View file

@ -0,0 +1,51 @@
defmodule AOC.Day9 do
use AOC.Day, day: 9
def parse_input(lines) do
Enum.map(lines, fn line ->
line
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
end)
end
def part1(histories) do
histories
|> Enum.map(&predict_next_value/1)
|> Enum.sum()
end
def part2(histories) do
Enum.map(histories, &predict_previous_value/1)
|> Enum.sum()
end
def predict_next_value(history) do
history
|> generate_differences()
|> Enum.map(&List.last/1)
|> Enum.sum()
end
def predict_previous_value(history) do
history
|> generate_differences()
|> Enum.map(&List.first/1)
|> Enum.reduce(&Kernel.-/2)
end
def generate_differences(history), do: generate_differences(history, [history])
def generate_differences(numbers, acc) do
if Enum.all?(numbers, &(&1 == 0)) do
acc
else
differences =
numbers
|> Enum.chunk_every(2, 1, :discard)
|> Enum.map(fn [val1, val2] -> val2 - val1 end)
generate_differences(differences, [differences | acc])
end
end
end