2024 Day 15 Part 2 😵
This commit is contained in:
parent
4937115328
commit
0825d8db0e
1 changed files with 136 additions and 6 deletions
142
2024/day15.exs
142
2024/day15.exs
|
@ -2,10 +2,8 @@
|
|||
defmodule Day15 do
|
||||
def part1({warehouse, robot, moves}) do
|
||||
attempt_moves(moves, robot, warehouse)
|
||||
|> Enum.map(fn
|
||||
{{x, y}, :box} -> x + y * 100
|
||||
_ -> 0
|
||||
end)
|
||||
|> Enum.filter(&match?({_, :box}, &1))
|
||||
|> Enum.map(fn {{x, y}, :box} -> x + y * 100 end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
|
@ -47,8 +45,140 @@ defmodule Day15 do
|
|||
end
|
||||
end
|
||||
|
||||
def part2(_input) do
|
||||
:boring_skipped
|
||||
def part2({warehouse, {x, y}, moves}) do
|
||||
bigger_warehouse =
|
||||
Enum.reduce(warehouse, %{}, fn {{x, y}, v}, bigger ->
|
||||
{left, right} =
|
||||
case v do
|
||||
:box -> {{:box, :left}, {:box, :right}}
|
||||
:wall -> {:wall, :wall}
|
||||
end
|
||||
|
||||
bigger |> Map.put({x * 2, y}, left) |> Map.put({x * 2 + 1, y}, right)
|
||||
end)
|
||||
|
||||
robot = {x * 2, y}
|
||||
|
||||
attempt_moves2(moves, robot, bigger_warehouse)
|
||||
|> Enum.filter(&match?({_, {:box, :left}}, &1))
|
||||
|> Enum.map(fn {{x, y}, {:box, :left}} -> x + y * 100 end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def attempt_moves2([], _robot, warehouse), do: warehouse
|
||||
|
||||
def attempt_moves2([move | next_moves], robot, warehouse) do
|
||||
next = move.(robot)
|
||||
|
||||
case Map.fetch(warehouse, next) do
|
||||
:error ->
|
||||
attempt_moves2(next_moves, next, warehouse)
|
||||
|
||||
{:ok, :wall} ->
|
||||
attempt_moves2(next_moves, robot, warehouse)
|
||||
|
||||
{:ok, {:box, side}} ->
|
||||
case get_pushable_boxes2(next, side, move, warehouse, [{next, side}]) do
|
||||
:wall ->
|
||||
attempt_moves2(next_moves, robot, warehouse)
|
||||
|
||||
boxes ->
|
||||
new_boxes = Map.new(boxes, fn {box, side} -> {move.(box), {:box, side}} end)
|
||||
|
||||
warehouse =
|
||||
warehouse
|
||||
|> Map.drop(Enum.map(boxes, &elem(&1, 0)))
|
||||
|> Map.merge(new_boxes)
|
||||
|
||||
attempt_moves2(next_moves, next, warehouse)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# need to account for 2-width boxes when pushing vertically
|
||||
# @<--pushing down moves down all RHS of stack
|
||||
# [][][][]
|
||||
# [][][] @
|
||||
# [][] []<--make sure RHS moves too
|
||||
# []
|
||||
# @<- pushing up pushes all
|
||||
def get_pushable_boxes2(box, side, move, warehouse, pushable_boxes) do
|
||||
next = move.(box)
|
||||
|
||||
case abs(elem(next, 1) - elem(box, 1)) do
|
||||
# horizontal
|
||||
0 ->
|
||||
case Map.fetch(warehouse, next) do
|
||||
:error ->
|
||||
pushable_boxes
|
||||
|
||||
{:ok, :wall} ->
|
||||
:wall
|
||||
|
||||
{:ok, {:box, next_side}} ->
|
||||
get_pushable_boxes2(next, next_side, move, warehouse, [
|
||||
{next, next_side} | pushable_boxes
|
||||
])
|
||||
end
|
||||
|
||||
# vertical
|
||||
1 ->
|
||||
{x, y} = box
|
||||
|
||||
{other_box, other_side} =
|
||||
case side do
|
||||
:left -> {{x + 1, y}, :right}
|
||||
:right -> {{x - 1, y}, :left}
|
||||
end
|
||||
|
||||
other_next = move.(other_box)
|
||||
|
||||
pushable_boxes = [{other_box, other_side} | pushable_boxes]
|
||||
|
||||
side
|
||||
|> case do
|
||||
:left ->
|
||||
{{Map.fetch(warehouse, next), Map.fetch(warehouse, other_next)}, next, other_next}
|
||||
|
||||
:right ->
|
||||
{{Map.fetch(warehouse, other_next), Map.fetch(warehouse, next)}, other_next, next}
|
||||
end
|
||||
|> case do
|
||||
{{:error, :error}, _, _} ->
|
||||
pushable_boxes
|
||||
|
||||
{{{:ok, :wall}, _}, _, _} ->
|
||||
:wall
|
||||
|
||||
{{_, {:ok, :wall}}, _, _} ->
|
||||
:wall
|
||||
|
||||
{{{:ok, {:box, side}}, :error}, left, _right} ->
|
||||
get_pushable_boxes2(left, side, move, warehouse, [{left, side} | pushable_boxes])
|
||||
|
||||
{{:error, {:ok, {:box, side}}}, _left, right} ->
|
||||
get_pushable_boxes2(right, side, move, warehouse, [{right, side} | pushable_boxes])
|
||||
|
||||
{{{:ok, {:box, :left}}, {:ok, {:box, :right}}}, left, _} ->
|
||||
# if left-right, just one box, only need to check one side
|
||||
# []
|
||||
# []
|
||||
get_pushable_boxes2(left, :left, move, warehouse, [{left, :left} | pushable_boxes])
|
||||
|
||||
{{{:ok, {:box, :right}}, {:ok, {:box, :left}}}, left, right} ->
|
||||
# if right-left, two boxes, so need to check both...
|
||||
# [][]
|
||||
# []
|
||||
left = get_pushable_boxes2(left, :right, move, warehouse, [{left, :right}])
|
||||
right = get_pushable_boxes2(right, :left, move, warehouse, [{right, :left}])
|
||||
|
||||
if left == :wall or right == :wall do
|
||||
:wall
|
||||
else
|
||||
pushable_boxes ++ left ++ right
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def input do
|
||||
|
|
Loading…
Reference in a new issue