day 16 + day 17
This commit is contained in:
parent
809ae69b0c
commit
092bb05312
7 changed files with 575 additions and 0 deletions
103
23/elixir/lib/days/day16.ex
Normal file
103
23/elixir/lib/days/day16.ex
Normal file
|
@ -0,0 +1,103 @@
|
|||
defmodule AOC.Day16 do
|
||||
use AOC.Day, day: 16
|
||||
|
||||
def parse_input(lines) do
|
||||
lines
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {line, y} ->
|
||||
line
|
||||
|> String.to_charlist()
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {space, x} ->
|
||||
{{y, x}, space}
|
||||
end)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
end
|
||||
|
||||
def new_location({y, x}, :north), do: {y - 1, x}
|
||||
def new_location({y, x}, :east), do: {y, x + 1}
|
||||
def new_location({y, x}, :south), do: {y + 1, x}
|
||||
def new_location({y, x}, :west), do: {y, x - 1}
|
||||
|
||||
def new_directions(:north, ?\\), do: [:west]
|
||||
def new_directions(:north, ?/), do: [:east]
|
||||
def new_directions(:north, ?-), do: [:east, :west]
|
||||
def new_directions(:east, ?\\), do: [:south]
|
||||
def new_directions(:east, ?/), do: [:north]
|
||||
def new_directions(:east, ?|), do: [:south, :north]
|
||||
def new_directions(:south, ?\\), do: [:east]
|
||||
def new_directions(:south, ?/), do: [:west]
|
||||
def new_directions(:south, ?-), do: [:east, :west]
|
||||
def new_directions(:west, ?\\), do: [:north]
|
||||
def new_directions(:west, ?/), do: [:south]
|
||||
def new_directions(:west, ?|), do: [:south, :north]
|
||||
def new_directions(direction, _), do: [direction]
|
||||
|
||||
def simulate_laser(grid, location, direction) do
|
||||
case :ets.lookup(:laser_memo, {location, direction}) do
|
||||
[] ->
|
||||
:ets.insert_new(:laser_memo, {{location, direction}, true})
|
||||
new_location = new_location(location, direction)
|
||||
|
||||
case Map.fetch(grid, new_location) do
|
||||
{:ok, symbol} ->
|
||||
new_directions(direction, symbol)
|
||||
|> Enum.each(&simulate_laser(grid, new_location, &1))
|
||||
|
||||
:error ->
|
||||
:ok
|
||||
end
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def count_energized(grid, start_location, direction) do
|
||||
:ets.new(:laser_memo, [:named_table])
|
||||
|
||||
simulate_laser(grid, start_location, direction)
|
||||
|
||||
count =
|
||||
:ets.tab2list(:laser_memo)
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.uniq()
|
||||
|> Enum.count()
|
||||
|
||||
:ets.delete(:laser_memo)
|
||||
|
||||
count - 1
|
||||
end
|
||||
|
||||
def part1(grid) do
|
||||
count_energized(grid, {0, -1}, :east)
|
||||
end
|
||||
|
||||
def part2(grid) do
|
||||
max_x =
|
||||
grid
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.map(&elem(&1, 1))
|
||||
|> Enum.max()
|
||||
|
||||
max_y =
|
||||
grid
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.map(&elem(&1, 0))
|
||||
|> Enum.max()
|
||||
|
||||
[
|
||||
Enum.map(0..max_x, fn x -> {{-1, x}, :south} end),
|
||||
Enum.map(0..max_x, fn x -> {{max_y + 1, x}, :north} end),
|
||||
Enum.map(0..max_y, fn y -> {{y, -1}, :east} end),
|
||||
Enum.map(0..max_y, fn y -> {{y, max_x + 1}, :west} end)
|
||||
]
|
||||
|> List.flatten()
|
||||
|> Enum.map(fn {position, direction} ->
|
||||
count_energized(grid, position, direction)
|
||||
end)
|
||||
|> Enum.max()
|
||||
end
|
||||
end
|
193
23/elixir/lib/days/day17.ex
Normal file
193
23/elixir/lib/days/day17.ex
Normal file
|
@ -0,0 +1,193 @@
|
|||
defmodule AOC.Day17 do
|
||||
use AOC.Day, day: 17
|
||||
# use AOC.Day, day: 17, input: "example2"
|
||||
|
||||
def parse_input(lines) do
|
||||
lines
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {line, y} ->
|
||||
line
|
||||
|> String.split("", trim: true)
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {heat_loss, x} ->
|
||||
{{y, x}, String.to_integer(heat_loss)}
|
||||
end)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
end
|
||||
|
||||
def turn(:north, :left), do: :west
|
||||
def turn(:north, :right), do: :east
|
||||
def turn(:east, :left), do: :north
|
||||
def turn(:east, :right), do: :south
|
||||
def turn(:south, :left), do: :east
|
||||
def turn(:south, :right), do: :west
|
||||
def turn(:west, :left), do: :south
|
||||
def turn(:west, :right), do: :north
|
||||
|
||||
def apply_direction({y, x}, :north), do: {y - 1, x}
|
||||
def apply_direction({y, x}, :east), do: {y, x + 1}
|
||||
def apply_direction({y, x}, :south), do: {y + 1, x}
|
||||
def apply_direction({y, x}, :west), do: {y, x - 1}
|
||||
|
||||
def simulate_movement(map, goal, min_straight, max_straight) do
|
||||
simulate_movement(map, goal, min_straight, max_straight, {0, 1}, :east, 1, 0, %{})
|
||||
simulate_movement(map, goal, min_straight, max_straight, {1, 0}, :south, 1, 0, %{})
|
||||
end
|
||||
|
||||
def simulate_movement(
|
||||
_map,
|
||||
_goal,
|
||||
_,
|
||||
_,
|
||||
position,
|
||||
_direction,
|
||||
_straight_count,
|
||||
_heat_loss,
|
||||
visited
|
||||
)
|
||||
when is_map_key(visited, position),
|
||||
do: :ok
|
||||
|
||||
def simulate_movement(
|
||||
map,
|
||||
goal,
|
||||
min_straight,
|
||||
max_straight,
|
||||
position,
|
||||
direction,
|
||||
straight_count,
|
||||
heat_loss,
|
||||
visited
|
||||
) do
|
||||
case Map.fetch(map, position) do
|
||||
{:ok, extra_heat_loss} ->
|
||||
heat_loss = heat_loss + extra_heat_loss
|
||||
|
||||
better_heat_loss? =
|
||||
case :ets.lookup(:movement_memo, {position, direction, straight_count}) do
|
||||
[] ->
|
||||
true
|
||||
|
||||
[{_, heat_loss_memo}] ->
|
||||
heat_loss < heat_loss_memo
|
||||
end
|
||||
|
||||
if better_heat_loss? do
|
||||
if position == goal do
|
||||
if straight_count >= min_straight do
|
||||
:ets.insert(:movement_memo, {{position, direction, straight_count}, heat_loss})
|
||||
|
||||
case :ets.lookup(:best_memo, :best) do
|
||||
[] ->
|
||||
IO.puts("BEST: #{heat_loss}")
|
||||
:ets.insert(:best_memo, {:best, heat_loss})
|
||||
|
||||
[{:best, best}] when heat_loss < best ->
|
||||
IO.puts("BEST: #{heat_loss}")
|
||||
:ets.insert(:best_memo, {:best, heat_loss})
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
else
|
||||
:ets.insert(:movement_memo, {{position, direction, straight_count}, heat_loss})
|
||||
|
||||
worse_than_best =
|
||||
case :ets.lookup(:best_memo, :best) do
|
||||
[] -> false
|
||||
[{:best, best}] -> heat_loss > best
|
||||
end
|
||||
|
||||
if not worse_than_best do
|
||||
if straight_count < max_straight do
|
||||
simulate_movement(
|
||||
map,
|
||||
goal,
|
||||
min_straight,
|
||||
max_straight,
|
||||
apply_direction(position, direction),
|
||||
direction,
|
||||
straight_count + 1,
|
||||
heat_loss,
|
||||
Map.put(visited, position, true)
|
||||
)
|
||||
end
|
||||
|
||||
if straight_count >= min_straight do
|
||||
new_direction = turn(direction, :left)
|
||||
|
||||
simulate_movement(
|
||||
map,
|
||||
goal,
|
||||
min_straight,
|
||||
max_straight,
|
||||
apply_direction(position, new_direction),
|
||||
new_direction,
|
||||
1,
|
||||
heat_loss,
|
||||
Map.put(visited, position, true)
|
||||
)
|
||||
|
||||
new_direction = turn(direction, :right)
|
||||
|
||||
simulate_movement(
|
||||
map,
|
||||
goal,
|
||||
min_straight,
|
||||
max_straight,
|
||||
apply_direction(position, new_direction),
|
||||
new_direction,
|
||||
1,
|
||||
heat_loss,
|
||||
Map.put(visited, position, true)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def part1(map) do
|
||||
:ets.new(:movement_memo, [:named_table])
|
||||
:ets.new(:best_memo, [:named_table])
|
||||
|
||||
goal = Enum.map(map, &elem(&1, 0)) |> Enum.max()
|
||||
simulate_movement(map, goal, 1, 3)
|
||||
|
||||
best =
|
||||
:ets.tab2list(:movement_memo)
|
||||
|> Enum.filter(fn {{position, _, _}, _} -> position == goal end)
|
||||
|> Enum.map(fn {_, heat_loss} -> heat_loss end)
|
||||
|> Enum.min()
|
||||
|
||||
:ets.delete(:movement_memo)
|
||||
:ets.delete(:best_memo)
|
||||
|
||||
best
|
||||
end
|
||||
|
||||
def part2(map) do
|
||||
:ets.new(:movement_memo, [:named_table])
|
||||
:ets.new(:best_memo, [:named_table])
|
||||
|
||||
goal = Enum.map(map, &elem(&1, 0)) |> Enum.max()
|
||||
simulate_movement(map, goal, 4, 10)
|
||||
|
||||
best =
|
||||
:ets.tab2list(:movement_memo)
|
||||
|> Enum.filter(fn {{position, _, _}, _} -> position == goal end)
|
||||
|> Enum.map(fn {_, heat_loss} -> heat_loss end)
|
||||
|> Enum.min()
|
||||
|
||||
:ets.delete(:movement_memo)
|
||||
:ets.delete(:best_memo)
|
||||
|
||||
best
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue