From bfd65557bf8a39063b3b4ce7f59dca03ea3b2554 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 16 Dec 2024 11:33:17 +0000 Subject: [PATCH] 2024 day 16 part 2 Quite slow takes ~11 mins to run. --- bin/day2416.ml | 84 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/bin/day2416.ml b/bin/day2416.ml index 3e335c1..d9c14b6 100644 --- a/bin/day2416.ml +++ b/bin/day2416.ml @@ -5,15 +5,15 @@ let find grid c = let input_of_file fname = let grid = Aoc.Grid.of_file fname in - let start_state = (find grid 'S', (1, 0)) in - (grid, start_state) + let start_pos = find grid 'S' in + (grid, start_pos) let rec dijkstra visit check_end states = let compare_costs (lhs, _) (rhs, _) = compare lhs rhs in match states with - | [] -> failwith "dijkstra" + | [] -> None | (cost, state) :: t -> - if check_end state then cost + if check_end state then Some (cost, state, t) else let new_states = visit cost state |> List.sort compare_costs @@ -21,7 +21,7 @@ let rec dijkstra visit check_end states = in dijkstra visit check_end new_states -let visited_idx grid (p, (dx, dy)) = +let visited_idx grid ((dx, dy), p) = let add = match (dx, dy) with | 1, 0 -> 0 @@ -32,27 +32,69 @@ let visited_idx grid (p, (dx, dy)) = in (Aoc.Grid.idx_of_pos grid p * 4) + add -let has_visited grid visited_grid state = visited_grid.(visited_idx grid state) - -let mark_visited grid visited_grid state = - visited_grid.(visited_idx grid state) <- true - -let visit grid visited_grid cost ((((x, y) as p), (dx, dy)) as state) = - if has_visited grid visited_grid state then [] +let visit grid visited_grid cost state = + let (dx, dy), ((x, y) as p) = List.hd state in + let has_visited = visited_grid.(visited_idx grid (List.hd state)) in + if has_visited then [] else if Aoc.Grid.get_by_pos grid p = '#' then [] else ( - Printf.printf "%d %d %d %d %d\n" cost x y dx dy; - mark_visited grid visited_grid state; + visited_grid.(visited_idx grid (List.hd state)) <- true; [ - (cost + 1, ((x + dx, y + dy), (dx, dy))); - (cost + 1000, (p, (-dy, dx))); - (cost + 1000, (p, (dy, -dx))); + (cost + 1, ((dx, dy), (x + dx, y + dy)) :: state); + (cost + 1000, ((-dy, dx), p) :: state); + (cost + 1000, ((dy, -dx), p) :: state); ]) -let check_end grid (p, _) = Aoc.Grid.get_by_pos grid p = 'E' +let visit_max grid visited_grid max_cost cost state = + let has_visited = visited_grid.(visited_idx grid (List.hd state)) < cost in + let (dx, dy), ((x, y) as p) = List.hd state in + if has_visited then [] + else if cost > max_cost then [] + else if Aoc.Grid.get_by_pos grid p = '#' then [] + else ( + (*Printf.printf "%d (%d, %d)\n" cost x y; + flush stdout;*) + visited_grid.(visited_idx grid (List.hd state)) <- cost; + [ + (cost + 1, ((dx, dy), (x + dx, y + dy)) :: state); + (cost + 1000, ((-dy, dx), p) :: state); + (cost + 1000, ((dy, -dx), p) :: state); + ]) -let part (grid, start_state) = +let[@warning "-32"] print_point (x, y) = Printf.printf "(%d, %d)" x y + +let check_end grid state = + let _, p = List.hd state in + Aoc.Grid.get_by_pos grid p = 'E' + +let check_end2 grid _ state = check_end grid state + +let part1 (grid, start_pos) = let visited_grid = Array.make (Aoc.Grid.length grid * 4) false in - dijkstra (visit grid visited_grid) (check_end grid) [ (0, start_state) ] + match + dijkstra (visit grid visited_grid) (check_end grid) + [ (0, [ ((1, 0), start_pos) ]) ] + with + | None -> failwith "part" + | Some (cost, _, _) -> cost -let _ = Aoc.main input_of_file [ (string_of_int, part) ] +let part2 (grid, start_pos) = + let cost = part1 (grid, start_pos) in + let visited_grid = Array.make (Aoc.Grid.length grid * 4) max_int in + let rec impl acc lst = + match + dijkstra + (visit_max grid visited_grid cost) + (check_end2 grid visited_grid) + lst + with + | None -> acc + | Some (_, states, remainder) -> + List.iter (fun x -> visited_grid.(visited_idx grid x) <- 0) states; + impl (states :: acc) remainder + in + impl [] [ (0, [ ((1, 0), start_pos) ]) ] + |> List.concat |> List.map snd |> List.sort_uniq compare |> List.length + +let _ = + Aoc.main input_of_file [ (string_of_int, part1); (string_of_int, part2) ]