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
|
defmodule Day15 do
|
||||||
def part1({warehouse, robot, moves}) do
|
def part1({warehouse, robot, moves}) do
|
||||||
attempt_moves(moves, robot, warehouse)
|
attempt_moves(moves, robot, warehouse)
|
||||||
|> Enum.map(fn
|
|> Enum.filter(&match?({_, :box}, &1))
|
||||||
{{x, y}, :box} -> x + y * 100
|
|> Enum.map(fn {{x, y}, :box} -> x + y * 100 end)
|
||||||
_ -> 0
|
|
||||||
end)
|
|
||||||
|> Enum.sum()
|
|> Enum.sum()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -47,8 +45,140 @@ defmodule Day15 do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def part2(_input) do
|
def part2({warehouse, {x, y}, moves}) do
|
||||||
:boring_skipped
|
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
|
end
|
||||||
|
|
||||||
def input do
|
def input do
|
||||||
|
|
Loading…
Reference in a new issue