From 42911c032dde294bf9a55968e5560969264aa6fe Mon Sep 17 00:00:00 2001 From: Adam Millerchip Date: Mon, 16 Dec 2024 02:55:05 +0900 Subject: [PATCH] =?UTF-8?q?2024=20Day=2015=20Part=202=20=F0=9F=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 2024/day15.exs | 175 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 2 deletions(-) diff --git a/2024/day15.exs b/2024/day15.exs index e639cb4..c748167 100755 --- a/2024/day15.exs +++ b/2024/day15.exs @@ -47,8 +47,179 @@ 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} + + warehouse = attempt_moves2(moves, robot, bigger_warehouse) + # dbg(Enum.filter(warehouse, &match?({_, {:box, _}}, &1))) + + warehouse + |> Enum.map(fn + {{x, y}, {:box, :left}} -> x + y * 100 + _ -> 0 + end) + |> Enum.sum() + end + + def attempt_moves2([], robot, warehouse) do + # dbg(robot) + warehouse + end + + def attempt_moves2([move | next_moves], robot, warehouse) do + warehouse = Map.put(warehouse, robot, :robot) + + # for y <- 0..19 do + # for x <- 0..19 do + # case Map.fetch(warehouse, {x, y}) do + # :error -> IO.write(" ") + # {:ok, :wall} -> IO.write("#") + # {:ok, {:box, :left}} -> IO.write("[") + # {:ok, {:box, :right}} -> IO.write("]") + # {:ok, :robot} -> IO.write("@") + # end + # end + + # IO.write("\n") + # end + + warehouse = Map.delete(warehouse, robot) + + # IO.gets("next?") + + next = move.(robot) + # dbg(Enum.filter(warehouse, &match?({_, {:box, _}}, &1))) + + 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 -> + # IO.puts("moving boxes...") + # dbg(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) + + # IO.puts("trying to push #{inspect(box)} (#{side}) to #{inspect(next)}") + + 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) + # IO.puts("bringing #{inspect(other_box)} (#{other_side}) too") + + pushable_boxes = [{other_box, other_side} | pushable_boxes] + + side + |> case do + :left -> + # IO.puts("checking #{inspect(next)}, #{inspect(other_next)}") + {{Map.fetch(warehouse, next), Map.fetch(warehouse, other_next)}, next, other_next} + + :right -> + # IO.puts("checking #{inspect(other_next)}, #{inspect(next)}") + {{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 + # [] + # [] + IO.puts("box is straight above") + 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... + # [][] + # [] + IO.puts("two boxes above") + 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