From 4eb967fd888fb1ba9cb3de145bbbf328d049110e Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Wed, 18 Dec 2024 10:30:43 +0000 Subject: [PATCH] Use binary search for 2024 day 18 part 2. This dramatically speeds the search up (by ~100x). --- bin/day2418.ml | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/bin/day2418.ml b/bin/day2418.ml index 4997046..3e8b355 100644 --- a/bin/day2418.ml +++ b/bin/day2418.ml @@ -110,12 +110,31 @@ let part1 count rocks = [grid] which makes it impossible to get from the top-left to bottom-right. *) let part2 start_count grid = - let rec impl count = - match find_route_length count grid with - | None -> count - | Some _ -> impl (count + 1) + (* Implementation notes: + + We do this by binary search in impl. The left_count is a known count of + rocks that is passable, right_count is a known count that is impassable. + + Once left_count + 1 = right_count we know that right_count is the first + rock to fall that causes the route to be blocked. + + count_rocks is used to find the number of rocks (and so give an initial + right_count). + *) + let rec count_rocks acc idx = + if idx >= Array.length grid.grid then acc + else if grid.grid.(idx) = max_int then count_rocks acc (idx + 1) + else count_rocks (max acc grid.grid.(idx)) (idx + 1) in - let count = impl start_count in + let rec impl left_count right_count = + if right_count - left_count = 1 then right_count + else + let count = (left_count + right_count) / 2 in + match find_route_length count grid with + | None -> impl left_count count + | Some _ -> impl count right_count + in + let count = impl start_count (1 + count_rocks 0 0) in match Array.find_index (( = ) (count - 1)) grid.grid with | None -> failwith "part2" | Some idx -> idx