add day 14
This commit is contained in:
parent
4b59c0f893
commit
d9aee9105d
3 changed files with 224 additions and 0 deletions
114
23/elixir/lib/days/day14.ex
Normal file
114
23/elixir/lib/days/day14.ex
Normal file
|
@ -0,0 +1,114 @@
|
|||
defmodule AOC.Day14 do
|
||||
use AOC.Day, day: 14
|
||||
|
||||
@compile {:parse_transform, :ms_transform}
|
||||
|
||||
def parse_input(lines) do
|
||||
dish_table = :ets.new(:dish_table, [])
|
||||
|
||||
lines
|
||||
|> Enum.with_index()
|
||||
|> Enum.each(fn {line, y} ->
|
||||
line
|
||||
|> String.to_charlist()
|
||||
|> Enum.with_index()
|
||||
|> Enum.each(fn
|
||||
{?O, x} -> :ets.insert(dish_table, {{y, x}, :round})
|
||||
{?#, x} -> :ets.insert(dish_table, {{y, x}, :cube})
|
||||
{?., _x} -> :ok
|
||||
end)
|
||||
end)
|
||||
|
||||
max_y =
|
||||
:ets.tab2list(dish_table)
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.max()
|
||||
|
||||
max_x =
|
||||
:ets.tab2list(dish_table)
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.map(&elem(&1, 1))
|
||||
|> Enum.max()
|
||||
|
||||
{dish_table, {max_y, max_x}}
|
||||
end
|
||||
|
||||
def get_round_rock_coords(dish_table) do
|
||||
:ets.select(dish_table, :ets.fun2ms(fn {coords, type} when type == :round -> coords end))
|
||||
end
|
||||
|
||||
def perform_spin_cycle(dish_table, max_coords) do
|
||||
slide(dish_table, max_coords, fn {y1, _}, {y2, _} -> y1 <= y2 end, fn {y, x} ->
|
||||
{y - 1, x}
|
||||
end)
|
||||
|
||||
slide(dish_table, max_coords, fn {_, x1}, {_, x2} -> x1 <= x2 end, fn {y, x} ->
|
||||
{y, x - 1}
|
||||
end)
|
||||
|
||||
slide(dish_table, max_coords, fn {y1, _}, {y2, _} -> y1 >= y2 end, fn {y, x} ->
|
||||
{y + 1, x}
|
||||
end)
|
||||
|
||||
slide(dish_table, max_coords, fn {_, x1}, {_, x2} -> x1 >= x2 end, fn {y, x} ->
|
||||
{y, x + 1}
|
||||
end)
|
||||
end
|
||||
|
||||
def slide(dish_table, max_coords, sort_fun, slide_fun) do
|
||||
get_round_rock_coords(dish_table)
|
||||
|> Enum.sort(sort_fun)
|
||||
|> Enum.each(&slide_rock(dish_table, max_coords, slide_fun, &1))
|
||||
end
|
||||
|
||||
def slide_rock(dish_table, {max_y, max_x} = max_coords, slide_fun, coords) do
|
||||
{slide_y, slide_x} = slide_coords = slide_fun.(coords)
|
||||
|
||||
if not (slide_y < 0 or slide_x < 0 or slide_y > max_y or slide_x > max_x) do
|
||||
case :ets.lookup(dish_table, slide_coords) do
|
||||
[] ->
|
||||
:ets.delete(dish_table, coords)
|
||||
:ets.insert(dish_table, {slide_coords, :round})
|
||||
slide_rock(dish_table, max_coords, slide_fun, slide_coords)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def calculate_total_load(dish_table, {max_y, _}) do
|
||||
get_round_rock_coords(dish_table)
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.map(&(max_y + 1 - &1))
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part1({dish_table, max_coords}) do
|
||||
slide(dish_table, max_coords, fn {y1, _}, {y2, _} -> y1 <= y2 end, fn {y, x} ->
|
||||
{y - 1, x}
|
||||
end)
|
||||
|
||||
calculate_total_load(dish_table, max_coords)
|
||||
end
|
||||
|
||||
def part2({dish_table, max_coords}) do
|
||||
memo_table = :ets.new(:memo_table, [])
|
||||
|
||||
# Adjust according to calculations
|
||||
cycle_count = 109
|
||||
|
||||
Enum.each(1..cycle_count, fn i ->
|
||||
perform_spin_cycle(dish_table, max_coords)
|
||||
memo = get_round_rock_coords(dish_table) |> Enum.sort()
|
||||
|
||||
case :ets.lookup(memo_table, memo) do
|
||||
[] -> :ets.insert(memo_table, {memo, i})
|
||||
[{_, i_prev}] -> IO.puts("State already observed: #{i_prev} & #{i}")
|
||||
end
|
||||
end)
|
||||
|
||||
calculate_total_load(dish_table, max_coords)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue