From a780d279c0ff7e4350d8d70b27b10d985b37b3a8 Mon Sep 17 00:00:00 2001 From: Adam Millerchip Date: Sun, 29 Dec 2024 23:19:00 +0900 Subject: [PATCH] 2024 Day 6 part 2 --- 2024/day6.exs | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/2024/day6.exs b/2024/day6.exs index 68d378a..3deca43 100755 --- a/2024/day6.exs +++ b/2024/day6.exs @@ -2,6 +2,7 @@ defmodule Patrol do defstruct obstacles: MapSet.new(), visited: MapSet.new(), + path: MapSet.new(), x: 0, y: 0, max_x: nil, @@ -11,20 +12,32 @@ defmodule Patrol do end defmodule Day6 do - def part1(%Patrol{} = patrol) when patrol.x == patrol.max_x or patrol.y == patrol.max_y do - MapSet.size(patrol.visited) + def part1(patrol), do: MapSet.size(patrol(patrol).visited) + + def patrol(%Patrol{} = patrol) when patrol.x in [-1, patrol.max_x] or patrol.y in [-1, patrol.max_y] do + patrol end - def part1(%Patrol{} = patrol) do + def patrol(%Patrol{} = patrol) do next_x = patrol.x + patrol.dir_x next_y = patrol.y + patrol.dir_y - if MapSet.member?(patrol.obstacles, {next_x, next_y}) do - {dir_x, dir_y} = turn_right(patrol.dir_x, patrol.dir_y) - part1(%Patrol{patrol | dir_x: dir_x, dir_y: dir_y}) + patrol = + if MapSet.member?(patrol.obstacles, {next_x, next_y}) do + {dir_x, dir_y} = turn_right(patrol.dir_x, patrol.dir_y) + %Patrol{patrol | dir_x: dir_x, dir_y: dir_y} + else + visited = MapSet.put(patrol.visited, {patrol.x, patrol.y}) + %Patrol{patrol | x: next_x, y: next_y, visited: visited} + end + + next_path = {patrol.x, patrol.y, patrol.dir_x, patrol.dir_y} + + if MapSet.member?(patrol.path, next_path) do + :loop else - visited = MapSet.put(patrol.visited, {patrol.x, patrol.y}) - part1(%Patrol{patrol | x: next_x, y: next_y, visited: visited}) + patrol = %Patrol{patrol | path: MapSet.put(patrol.path, next_path)} + patrol(patrol) end end @@ -33,9 +46,20 @@ defmodule Day6 do def turn_right(0, 1), do: {-1, 0} def turn_right(-1, 0), do: {0, -1} - def part2(_input) do - # hmmmmmmm probably need completely different solution - :ok + def part2(patrol) do + completed_patrol = patrol(patrol) + + candidate_obstructions = + Enum.reduce(completed_patrol.visited, MapSet.new(), fn {x, y}, candidate_obstructions -> + Enum.into([{x - 1, y}, {x + 1, y}, {x, y - 1}, {x, y + 1}], candidate_obstructions) + end) + + Enum.count(candidate_obstructions, fn {x, y} -> + new_obstacles = MapSet.put(patrol.obstacles, {x, y}) + new_patrol = %Patrol{patrol | obstacles: new_obstacles} + + patrol(new_patrol) == :loop + end) end def input do