Compare commits

..
25 Commits
Author SHA1 Message Date
ryan 8ec58edd08 solve day 18!
it was kinda ez
2024-02-13 23:03:04 -08:00
ryan 1904239ca7 reorganize day 17 code a bit 2024-01-11 10:48:11 -08:00
ryan 46d49dc3fe add pretty printed tower test in day 17 2024-01-11 10:19:39 -08:00
ryan 950f2860df fix day 12 performance regerssion
caused by a change to Grid.at_e that would eagerly format an exception
string even if the function never throws an exception.
2024-01-08 12:48:55 -08:00
ryan d203c9a520 finish day 17 part 2 2024-01-08 12:36:14 -08:00
ryan 8b54ae782c finish day 17 part 1 2024-01-05 11:33:26 -08:00
ryan 9f1499a1d3 implement day 17 rock falling logic 2024-01-04 00:38:09 -08:00
ryan 490696c63d make Grid.draw more flexible
- printer callback includes Vec2.t in the arguments now
- added optional rev_x and rev_y params
2024-01-03 09:18:57 -08:00
ryan a7c039197b fix .ocamlinit ?? 2024-01-03 09:18:27 -08:00
ryan 94f4badcc4 30x speedup on 16.2 from using bitmasks as a set!! 2023-12-04 23:28:54 -08:00
rmanseau 4e57ad4072 clean up 15.1 implementation a bit 2023-11-27 13:45:32 -08:00
ryan f2f3e497d6 get rid of old day 16 solution 2023-11-23 21:35:32 -08:00
ryan 2a515a5323 day 16.1 down to 1.5 seconds !! 2023-11-23 12:22:17 -08:00
ryan 5c0d7867a4 speed up 16.2 by 10x but its still 10 seconds >:( 2023-11-23 11:17:41 -08:00
ryan 1df5532c24 finally solved day 16 part 2 (in 100 seconds :P) 2023-11-22 22:58:22 -08:00
ryan 8db68c9baf use djikstra to get min dist between all valves
now i should be able to rewrite traverse in a way that doesn't suck
2023-11-22 18:27:42 -08:00
ryan 360be1a368 modify djikstra to work without a goal
if you give None as a goal, then it traverses the entire grid and finds
the shortest path to every node. the distances can then be queried via the
get_info that is passed in as an argument
2023-11-22 16:10:47 -08:00
ryan ae2acb87fa refactor generalized djikstra out of day 12 2023-11-22 16:10:47 -08:00
ryan c7eae53378 doesnt work for 16.2 :( 2023-11-21 23:22:43 -08:00
ryan b9a36a476a brute force day 16.1 with incorrect algorithm lol
it gets the right answer for the input but not for the example input
2023-11-21 18:17:35 -08:00
ryan 8270ee7aa8 never touching day 15 ever again 2023-11-21 16:50:51 -08:00
ryan 894e83fe12 fix day 15 for example inputs
part 1 didn't work for the example input :(
2023-11-21 16:48:03 -08:00
ryan 11546bff5f fix ocamlformat
apparently `version = x` simply refuses to format if you dont have the
specified version. doesn't seem very useful for a repo like this.
2023-11-21 16:47:17 -08:00
ryan d1e69ba66e cosmetic refactoring for day 15 2023-11-20 18:57:00 -08:00
ryan 2887274ad9 update the comment in day 15.1 2023-11-20 18:34:44 -08:00
14 changed files with 2772 additions and 113 deletions

No files matched your search

-1
View File
@@ -1,2 +1 @@
profile = janestreet profile = janestreet
version = 0.26.0
+1 -1
View File
@@ -1,2 +1,2 @@
#install_printer Aoc.Vec2.pp;; #install_printer Aoc.Vec2.pp;;
#install_printer Aoc.Vec2.pp_grid;; #install_printer Aoc.Grid.pp;;
+60
View File
@@ -0,0 +1,60 @@
Valve XB has flow rate=0; tunnels lead to valves WZ, LE
Valve BM has flow rate=0; tunnels lead to valves PL, RI
Valve GC has flow rate=0; tunnels lead to valves HN, IT
Valve RM has flow rate=0; tunnels lead to valves ZQ, YL
Valve ZM has flow rate=5; tunnels lead to valves SN, KE, UW, MY, GW
Valve UH has flow rate=0; tunnels lead to valves HM, HN
Valve GW has flow rate=0; tunnels lead to valves LE, ZM
Valve HN has flow rate=19; tunnels lead to valves UW, UH, GL, WZ, GC
Valve VT has flow rate=0; tunnels lead to valves ZD, PE
Valve VI has flow rate=0; tunnels lead to valves JS, AA
Valve YL has flow rate=12; tunnels lead to valves PM, MH, RM, CM
Valve LA has flow rate=0; tunnels lead to valves SN, IY
Valve CM has flow rate=0; tunnels lead to valves YL, UL
Valve JI has flow rate=24; tunnels lead to valves UV, WH, XW, OJ
Valve ZD has flow rate=25; tunnels lead to valves VB, XW, VT
Valve VB has flow rate=0; tunnels lead to valves QX, ZD
Valve FO has flow rate=0; tunnels lead to valves WH, PE
Valve JS has flow rate=0; tunnels lead to valves VI, IY
Valve RI has flow rate=0; tunnels lead to valves PE, BM
Valve XD has flow rate=14; tunnel leads to valve CP
Valve ES has flow rate=11; tunnels lead to valves GU, WU
Valve WZ has flow rate=0; tunnels lead to valves XB, HN
Valve HW has flow rate=0; tunnels lead to valves QY, LE
Valve KE has flow rate=0; tunnels lead to valves AA, ZM
Valve IY has flow rate=22; tunnels lead to valves JS, AB, LA, IT
Valve XW has flow rate=0; tunnels lead to valves ZD, JI
Valve BE has flow rate=0; tunnels lead to valves AB, LE
Valve QY has flow rate=23; tunnels lead to valves AM, HW, MY
Valve MH has flow rate=0; tunnels lead to valves YL, AM
Valve IT has flow rate=0; tunnels lead to valves GC, IY
Valve DA has flow rate=0; tunnels lead to valves QR, CP
Valve PM has flow rate=0; tunnels lead to valves LE, YL
Valve WU has flow rate=0; tunnels lead to valves SM, ES
Valve UL has flow rate=0; tunnels lead to valves CM, QR
Valve SM has flow rate=13; tunnel leads to valve WU
Valve XC has flow rate=0; tunnels lead to valves ZJ, AA
Valve OJ has flow rate=0; tunnels lead to valves GI, JI
Valve SN has flow rate=0; tunnels lead to valves LA, ZM
Valve WH has flow rate=0; tunnels lead to valves JI, FO
Valve UW has flow rate=0; tunnels lead to valves HN, ZM
Valve HM has flow rate=0; tunnels lead to valves UH, PE
Valve AB has flow rate=0; tunnels lead to valves BE, IY
Valve QR has flow rate=8; tunnels lead to valves WW, UL, DA
Valve UV has flow rate=0; tunnels lead to valves JI, FF
Valve ZQ has flow rate=20; tunnel leads to valve RM
Valve ZJ has flow rate=0; tunnels lead to valves PE, XC
Valve GL has flow rate=0; tunnels lead to valves HN, PL
Valve CP has flow rate=0; tunnels lead to valves DA, XD
Valve AM has flow rate=0; tunnels lead to valves QY, MH
Valve PL has flow rate=17; tunnels lead to valves GL, YE, BM, FF, QX
Valve YE has flow rate=0; tunnels lead to valves PL, AA
Valve PE has flow rate=4; tunnels lead to valves FO, RI, ZJ, VT, HM
Valve MY has flow rate=0; tunnels lead to valves QY, ZM
Valve QX has flow rate=0; tunnels lead to valves VB, PL
Valve GI has flow rate=0; tunnels lead to valves OJ, AA
Valve WW has flow rate=0; tunnels lead to valves GU, QR
Valve FF has flow rate=0; tunnels lead to valves UV, PL
Valve LE has flow rate=6; tunnels lead to valves HW, GW, XB, BE, PM
Valve GU has flow rate=0; tunnels lead to valves ES, WW
Valve AA has flow rate=0; tunnels lead to valves KE, GI, VI, YE, XC
+1
View File
@@ -0,0 +1 @@
><<<<>>>><>>><<><<<<>>>><<>>><>>><<<<>>>><<>>>><<<>>>><<<>>>><<<>>><<<<>><>><<<<>>><><<<><><>>>><<<<><<<<>><<<>>>><<>><><>>>><<<>>><<<>>><<>>>><>>>><>><>>><<>><><<<<><>><<<>>>><<<>>><<<>><>><<<>>><<<<>>>><><<<>>><<<>>><<<<><<<<>>><<<<>>><<<>>><<<<>>><<>>><<><<<>><<<>>><<<<><<<<>>><<<><<>>>><<<>><>>><<>>><<<><<<<>>><<><<<<>>>><<>>>><<>>>><<<<>>><><<<<><>><<<>>>><<<<>><>>>><>><>><>><<<>><<<>>>><<<>><<>><<<<><<<<><<>>>><<<<><<<>>><>><<<>>><<<><<<><<<<><<><<<>>><<<<>>>><<<<><<>><<<<>>><>>><<<<><<<>>>><<><>><<<<>><<<<>>>><<<><<<<><<<<>>><<<><<>>><>>><<<<>>><<>><<<<>>><<<><<<>><<<<>>>><<<<><<><<<<>>>><>>>><<<<>>>><<<>>>><<<><<>>><>>><<<<>><<<<>>><><>><<<>>>><<<<>><<<>><<>><<<>>><<<>>>><<<<>>>><<>>>><<>>>><><<<<>><<<<>>>><<<<>>><<<<>><>><<<>>><>>>><><<>><<>>><<<>>>><>>><<>><<<>><>>><>>><><>><>><<<><<<>>>><>><<<><<<>>><<<<><<>>>><<<><<<>>>><>><<<>>>><<<>>>><>>><><>>>><>><<><<<>>>><<>>>><<<>>><<<<>>><<<>><>>>><<<<>>>><>><<>>><<<<>>>><<<<><>>>><<>><<>>>><>><<<<>>>><<<<>><<<>>>><<>><><>><<<<>><<<>>>><<<>>><<>><><<<>>>><<>><>><<>><>><<<<>><<<>>><<<<>>><<>>>><<>>><<<<>>><>><<><<<>><>>><<<>><<<<>>>><<<>>><<>>><<<>>><<<<>>>><<<<>>><<<>>><<>>>><<>>><<<>>><<><<>>>><<>>>><<><<>>><<><<<>>>><<<<><<<<>><<<>>>><>>><<<<>>><<<<>>>><<>><<<<>>>><<<><<<><<>>>><<<>>>><<<>>>><<<>><<>>><>>><<<<>>><<<<>><<<>>><<<>><<<<>>><<<<><<><>>><<<<>>><<<<>>>><>><<<<>><<<<>>>><<<<><<<>>>><>><<<<><<<<>>>><>><<><<<>>><<>>><<<<>><<<><<<><>><<>>>><<<><<<<><<<>>>><<<<>><<>><<<<>>>><><<<><<<>>>><<>>>><<>><<<<>>>><><><<<<><><<>>><<><<>>><>>><<>><><<><<>>>><<<<><<<>>>><<>><><<>>>><<<<><><<<>>>><<>>><<<><<<>>>><>><<<<>>>><>>><<><>>>><>>>><<<><>>><>>>><<<>><<<>>><<<<>>>><<>>>><<<<>>>><<><>><<<<>><<<<>>><<>>><>>>><<><<>>><>>>><<><<><<><><<<>><>><<<<>>><<<>>>><<<><<<<>><>><>>><<<<><<<>>>><<<>>><><<<<>>><<<<><<<<>>>><>><>>><<<><<>><<<><>>><<<<>><><<<<><>><<>><<>><>><<<<><<<>><>>>><<>><<<<>>><><<<>><<>><<>><>>><>>>><<><>><<<<>>><>>><<>>><<>>>><<>><<<<>>><>><<<>>><<<>>><<<<>>>><<<><<<<>><<><<<><<<>>><<><<>><>><>>><<<>>><<>><<>>><<>><<>><>><<<<>>>><<<<>>><<<>>>><<<<>>><<<>><<<>><<<<>>>><<>><<<<><<<<>><<>>><><<><<<<>>>><><>>>><<<<>>>><<<<>>>><<>><<<<>>>><<<><>><<>>>><<>>>><<<<>>>><<<>>><>><<>>>><<<>>>><<<<>>><<<<>><<<<>>>><<>>><<>>>><>>><>>>><><>><<<<>>>><<<>>>><<<>><<>>><<<<>>><>>>><<>>>><<<><>>><><<>>>><<>>>><<<>>>><<<<><<<<>>>><>>>><>><<<>>><<<>>>><<<>><<<>>><>><<>>><<><><<><<>>>><>>><<<<>><><>><>>><<<<><>>><<<>>><<<><<<<>>><<<>><<<>>><<>>><<<<><<<<><>><><<<<>>><<<>><<>><<<>><<<<>><>><>>>><<>>><<<>><<<>><<<<>><><<<<>>><<<>>>><<<<>>><<>><>><<>>><><<>>><<<>>><<<>><<>>>><<<<>><<<<>>>><<<><<><<<<>><<<<>><<<>>>><>><<<><>>>><<>>>><<><<<>>>><<<<>><<<>>>><<>>><>><<<<>>>><<<<>>><>>>><<<<><<><<>><>><>>><<<><<<<><<<<>><<<>>><<<<>><<><<<<>>>><<<>>>><<<>>>><<<<>>><<><<>><<><<<<>>>><<<><<<<>>>><<>>><<<<>><>>>><<<<>><<<>>>><<><<<<>>>><<<>><>>>><><<<>><<<><<<>>><>>>><>>><<<<><<<<>>><<>>><<<>>><<<<><<<<>>>><<>>><<<>><<>>><><<<>>>><<><>>><<>><<<>>>><<<><>><<<>>><<>>>><<<>>>><>><<><>><<>>>><<<>>>><<<<>>>><<<>>><<<>><<<<><<<<>><><<><<<>><>>><<<<>>><<<<>><<<>>><<>><<<<><<<><<<><<<>>><<<<>>><<<<>><<>>><<>><<<<>>>><<>>>><<>>>><<>><>>><>>>><<>>>><<<>>><<<<>>><>>><>>>><<<>><<>>><<>>>><<>>>><<<>>><<>>><<<><<<>><>>>><<<>><>>><<<>>><>>>><>><<>>><<<<>>><<<<>><>>><<<<>>><<<<><<<>>><><>>><<<>>><>><>>>><<>>>><<<>><<>>><<>><<<<>><<<<><>>><<>><<<<>>><<<>>><<>>>><>>>><<<><>>>><<><><>>><<>>>><<<>>>><><>><<<<>><<<>>>><<<<><<<<>>>><<<<>><>>>><<<>>>><<><<>>>><<<<>>>><<<<>>><>><>>>><>>>><>><<>>>><>>>><<>>><<<<>>>><<>>><><<>>>><<>><<<<><<><>>>><<<<>><<><<><<>><<<><<<>><<<<>>><<<<>><<>><>>><<<<>>>><<<<>>>><<<<>>><><<<<><<<<><><<<<><<<<>>>><<<<>>>><><>>><<<<><<<<><<<><><<<<>><><<<><<<<>><>>><><><<<><>>><<><<>><<<>><<<>>>><<<<>>><<>><<<<><>>><>>><<>>>><<<<>>><<<>>>><<<>>>><<<>><<<>><<<<>>><<<<>><>>><<<<><>>>><<<>><>>><<>>><<<<>><<><<<>><>>><<<>><<<<>>><<<>>>><>>><><<<><<<>>>><<>>><<><>>>><>>>><<<<>>><><><>>>><<<<>><<<<>>><<>>><<<><<<>>>><<><<<>><<<>>>><<<<>>>><>>><<<>>><><<<>><<<<>><<<>>>><>><<><><<>><<<>><<<>>><<<<>>>><<<><<<<>><<<<>>>><<<<>>>><<><<<<>>><<<<>><<<<>><<<>><<<<>>><<>>>><<>>><>><<>>>><>>><>>><<<><>>>><<<>>><<<<><<<<>>><<><><>>>><<>>>><<>>>><<<<>>>><<><<><<<>>><<<>>>><<><<<><<>>><<<><<<>>>><<<<>>><<>>>><<>><><<<><<>><<>>><<<<>><>><<<>><<<<>><<<<><<>>><<><<<<>>>><<<>><<<<>><<>>>><>>>><>>><>>>><<<>>><<<>>>><<>>>><>><>><<<>><<<>>><<>>><<<<>>><<<<>>><<>>>><>>><>><<<<>>>><<>>>><<>>>><<<<>>>><>>>><><>>><<>>>><<<<><<>>>><<<<>><<<<>>>><<>><<<<><<<<>>><<<<>><<>>>><<<>>>><<<><>><<<><<>>><<<<>><<<>>><><<<<>><<<<>><>>><<<<>>><<<<>>>><>>>><<>>>><<>>><>>>><<<<>>><<>><<<><<><<<>>>><<<>>>><<<<><<>>><>><<<<><<<>>><>><><<<><<>>>><>>>><>><<>>><<>>>><<>>>><<<<>><<>><><<>>><<>><<>><<>>><>><<<<>>>><<>>>><<<<>>><<>><><<<><>><<<>><>>><>><<>>><><>>><<>>>><<<>>><<<<>>><<<>><<>><<<<>>><<<><<<>><<<<><<>><>><<<<>><<>>>><<<>><<<>>>><<<<>>>><<<<>><<>>><<<>>><<<>>>><<<<>>><<<<>>>><>><<<<>>>><<>>><><<>>>><<<<>>>><<<<>>>><>><<>><<<<><<<<>>><><>>><<<<>>><<><>>>><<<<><<<>>>><>>>><<<>>>><<<>>>><<>>><<>>><<<<><<<>><>>><<<><<<>>><Line truncated
+2025
View File
File diff suppressed because it is too large. Load diff
+63 -45
View File
@@ -1,7 +1,5 @@
open Containers open Containers
let infinity = 1000000000
type node = type node =
{ char : char { char : char
; mutable visited : bool ; mutable visited : bool
@@ -10,25 +8,20 @@ type node =
[@@deriving show] [@@deriving show]
let parse_grid start_anywhere = let parse_grid start_anywhere =
let s = ref @@ Vec2.origin in let start_nodes = ref [] in
let e = ref @@ Vec2.origin in let end_node = ref @@ Vec2.origin in
let unvisited = ref [] in
let grid = let grid =
Utils.lines_of_input 12 Utils.lines_of_input 12
|> Grid.of_lines (fun char -> { char; visited = false; distance = infinity }) |> Grid.of_lines (fun char -> { char; visited = false; distance = Int.max_int })
in in
Grid.iter grid (fun pos -> Grid.iter grid (fun pos ->
let n = Grid.at_e grid pos in let node = Grid.at_e grid pos in
match n.char with match node.char with
| 'E' -> e := pos | 'E' -> end_node := pos
| 'S' -> | 'S' -> start_nodes := pos :: !start_nodes
n.distance <- 0; | 'a' when start_anywhere -> start_nodes := pos :: !start_nodes
s := pos
| 'a' when start_anywhere ->
n.distance <- 0;
unvisited := pos :: !unvisited
| _ -> ()); | _ -> ());
grid, !e, !s, !unvisited grid, !end_node, !start_nodes
;; ;;
let reachable f t = let reachable f t =
@@ -41,42 +34,67 @@ let reachable f t =
Char.compare (height f) (height t) >= -1 Char.compare (height f) (height t) >= -1
;; ;;
let rec path grid goal current unvisited = let get_neighbors grid node_pos =
let current_node = Grid.at_e grid current in let node = Grid.at_e grid node_pos in
Vec2.directions Vec2.directions
|> List.map (fun dir -> Vec2.(current + dir)) |> Iter.of_list
|> List.iter (fun neighbor -> |> Iter.filter_map (fun dir ->
match Grid.at grid neighbor with let neighbor_pos = Vec2.(node_pos + dir) in
| Some node when (not node.visited) && reachable current_node.char node.char -> match Grid.at grid neighbor_pos with
let new_distance = current_node.distance + 1 in | Some neighbor when reachable node.char neighbor.char -> Some neighbor_pos
if new_distance < node.distance then node.distance <- new_distance; | _ -> None)
if Option.is_none @@ List.find_opt (fun x -> Vec2.(x = neighbor)) !unvisited ;;
then unvisited := neighbor :: !unvisited
| _ -> ()); let path_distance grid goal start_nodes =
current_node.visited <- true; let set_info position (dist, visited) =
unvisited let node = Grid.at_e grid position in
:= List.sort node.distance <- dist;
(fun a b -> node.visited <- visited
let a = Grid.at_e grid a in in
let b = Grid.at_e grid b in let get_info position =
a.distance - b.distance) let { char = _; distance; visited } = Grid.at_e grid position in
!unvisited; distance, visited
match !unvisited with in
| shortest :: _ when Vec2.(shortest = goal) -> Grid.at grid shortest Utils.djikstra
| shortest :: rest -> path grid goal shortest @@ ref rest ~set_info
| [] -> None ~get_info
~eq:Vec2.( = )
~get_weight:(fun _ _ -> 1)
~get_neighbors:(get_neighbors grid)
~goal
~start_nodes
|> Option.get_exn_or "couldn't find"
;; ;;
let%expect_test "Day 12.1" = let%expect_test "Day 12.1" =
let grid, e, s, unvisited = parse_grid false in let grid, goal, start_nodes = parse_grid false in
let solution = Option.get_exn_or "coulnd't find" @@ path grid e s @@ ref unvisited in Printf.printf "%i" @@ path_distance grid (Some goal) start_nodes;
Printf.printf "%d" solution.distance;
[%expect {| 497 |}] [%expect {| 497 |}]
;; ;;
let%expect_test "Day 12.2" = let%expect_test "Day 12.2" =
let grid, e, s, unvisited = parse_grid true in let grid, goal, start_nodes = parse_grid true in
let solution = Option.get_exn_or "coulnd't find" @@ path grid e s @@ ref unvisited in Printf.printf "%i" @@ path_distance grid (Some goal) start_nodes;
Printf.printf "%d" solution.distance;
[%expect {| 492 |}] [%expect {| 492 |}]
;; ;;
let%expect_test "Day 12 test" =
let grid, goal, start_nodes = parse_grid false in
let _ = path_distance grid None start_nodes in
let print_dist_to pos =
let node = Option.get_exn_or "invalid pos!" grid.Grid.%(pos) in
Printf.printf "%s %c %i\n" (Vec2.show pos) node.char node.distance
in
print_dist_to goal;
print_dist_to Vec2.(goal + right);
print_dist_to Vec2.(goal + down);
print_dist_to Vec2.(of_tuple (121, 23));
print_dist_to Vec2.(origin + right);
[%expect
{|
(149, 20) E 497
(150, 20) z 498
(149, 21) y 496
(121, 23) a 138
(1, 0) b 21 |}]
;;
+1 -1
View File
@@ -9,7 +9,7 @@ type tile =
| Path_L | Path_L
| Path_R | Path_R
let char_of_tile = function let char_of_tile _ = function
| Empty -> '-' | Empty -> '-'
| Rock -> '#' | Rock -> '#'
| Sand -> 'o' | Sand -> 'o'
+76 -55
View File
@@ -1,5 +1,23 @@
open Containers open Containers
let example_lines =
[ "Sensor at x=2, y=18: closest beacon is at x=-2, y=15"
; "Sensor at x=9, y=16: closest beacon is at x=10, y=16"
; "Sensor at x=13, y=2: closest beacon is at x=15, y=3"
; "Sensor at x=12, y=14: closest beacon is at x=10, y=16"
; "Sensor at x=10, y=20: closest beacon is at x=10, y=16"
; "Sensor at x=14, y=17: closest beacon is at x=10, y=16"
; "Sensor at x=8, y=7: closest beacon is at x=2, y=10"
; "Sensor at x=2, y=0: closest beacon is at x=2, y=10"
; "Sensor at x=0, y=11: closest beacon is at x=2, y=10"
; "Sensor at x=20, y=14: closest beacon is at x=25, y=17"
; "Sensor at x=17, y=20: closest beacon is at x=21, y=22"
; "Sensor at x=16, y=7: closest beacon is at x=15, y=3"
; "Sensor at x=14, y=3: closest beacon is at x=15, y=3"
; "Sensor at x=20, y=1: closest beacon is at x=15, y=3"
]
;;
type sensor = type sensor =
{ pos : Vec2.t { pos : Vec2.t
; beacon : Vec2.t ; beacon : Vec2.t
@@ -41,97 +59,91 @@ let could_be_beacon sensors ignore_known pos =
slope -1 passing thru bx + dist + 1, by slope -1 passing thru bx + dist + 1, by
slope -1 passing thru bx - dist - 1, by slope -1 passing thru bx - dist - 1, by
to find constant given slope, plug point into to find the constant given a slope, plug a point into
c = y - m*x c = y - m*x
constants are store separately for pos and neg slope boundaries constants are stored separately for boundaries with positive and negative
so that they can be handled separately slope so that they can be handled separately
p1 = y - bx - dist - 1 p1 = y - bx - dist - 1
p2 = y - bx + dist + 1 p2 = y - bx + dist + 1
n1 = y + bx + dist + 1 n1 = y + bx + dist + 1
n2 = y + bx - dist - 1 n2 = y + bx - dist - 1
]}*) ]}*)
let get_coeffs sensors = let get_consts sensors extra =
sensors sensors
|> Iter.fold |> Iter.fold
(fun (pos_coeffs, neg_coeffs) { pos; beacon = _; dist } -> (fun (p_slope_consts, n_slope_consts) { pos; beacon = _; dist } ->
let p1 = pos.y - pos.x + dist + 1 in let p1 = pos.y - pos.x + dist + extra in
let p2 = pos.y - pos.x - dist - 1 in let p2 = pos.y - pos.x - dist - extra in
let n1 = pos.y + pos.x + dist + 1 in let n1 = pos.y + pos.x + dist + extra in
let n2 = pos.y + pos.x - dist - 1 in let n2 = pos.y + pos.x - dist - extra in
Iter.( Iter.(
append pos_coeffs (of_list [ p1; p2 ]), append neg_coeffs (of_list [ n1; n2 ]))) ( append p_slope_consts (of_list [ p1; p2 ])
, append n_slope_consts (of_list [ n1; n2 ]) )))
(Iter.empty, Iter.empty) (Iter.empty, Iter.empty)
;; ;;
let%expect_test "Day 15.1" = let solve_part_1 lines scan_y =
let sensors = Utils.lines_of_input 15 |> Iter.of_list |> Iter.map parse_sensor in let sensors = lines |> Iter.of_list |> Iter.map parse_sensor in
let scan_y = 2000000 in let p_slope_consts, n_slope_consts = get_consts sensors 0 in
let pos_coeffs, neg_coeffs = get_coeffs sensors in
(*{[ (*{[
for a line y = c to intersect with a positive slope boundary: for a known y to intersect with a positive slope boundary:
y = c y = x + p
y = x + n x = y - p
c = x + p
x = c - p
and for a negative slop boundary and for a negative slope boundary:
y = c
y = -x + n y = -x + n
c = -x + n x = n - y
x = n - c
]}*) ]}*)
let intersection_xs = let intersection_xs =
Iter.append Iter.append
(Iter.map (fun p -> scan_y - p) pos_coeffs) (Iter.map (fun p -> scan_y - p) p_slope_consts)
(Iter.map (fun n -> n - scan_y) neg_coeffs) (Iter.map (fun n -> n - scan_y) n_slope_consts)
|> Iter.sort_uniq ~cmp:Int.compare |> Iter.sort_uniq ~cmp:Int.compare
in in
(* iterate thru the intersections by ascending x. let check x = could_be_beacon sensors false @@ Vec2.of_tuple (x, scan_y) in
if a point in the region can be a beacon,
then every point in the region is. *)
let rec count_not_beacons count xs = let rec count_not_beacons count xs =
match xs with match xs with
| lx :: hx :: rest -> | x :: next :: rest ->
let count = (* if there is a region [x+1, next), the value of check
if could_be_beacon sensors false @@ Vec2.of_tuple (lx + 1, scan_y) is the same for each point within it. intersection points
then count must be checked separately from the regions between them *)
else count + hx - lx let intersection = if check x then 0 else 1 in
in let region = if x + 1 < next && check (x + 1) then 0 else next - (x + 1) in
count_not_beacons count @@ (hx :: rest) count_not_beacons (count + intersection + region) (next :: rest)
| _ -> count | _ -> count
in in
let possible_beacons = count_not_beacons 0 @@ Iter.to_list intersection_xs in count_not_beacons 0 @@ Iter.to_list intersection_xs
Printf.printf "%i\n" @@ possible_beacons; ;;
let%expect_test "Day 15.1 example" =
Printf.printf "%i\n" @@ solve_part_1 example_lines 10;
[%expect {| 26 |}]
;;
let%expect_test "Day 15.1" =
Printf.printf "%i\n" @@ solve_part_1 (Utils.lines_of_input 15) 2000000;
[%expect {| 5525990 |}] [%expect {| 5525990 |}]
;; ;;
let%expect_test "Day 15.2" = let solve_part_2 lines range mult =
let sensors = Utils.lines_of_input 15 |> Iter.of_list |> Iter.map parse_sensor in let sensors = lines |> Iter.of_list |> Iter.map parse_sensor in
let mult = 4000000 in
let range = mult in
let in_bounds = Vec2.(in_bounds origin @@ of_tuple (range, range)) in let in_bounds = Vec2.(in_bounds origin @@ of_tuple (range, range)) in
let pos_coeffs, neg_coeffs = get_coeffs sensors in let p_slope_consts, n_slope_consts = get_consts sensors 1 in
(*{[ (*{[
boundaries only itersect if they have opposite slope. boundaries only itersect if they have opposite slope.
to find the intersection, set equations to be equal and solve. to find the intersection, set equations to be equal and solve.
y = 1*x + p y = x + p
y = -1*x + n // set equal y = -x + n // set equal
x + p = -x + n // add x x + p = -x + n // add x and subtract p
2x + p = n // subtract p
2x = n - p // divide 2 2x = n - p // divide 2
x = (n - p)/2 // substitute x into original -> x = (n - p)/2 // substitute x into original
y = (n - p)/2 + p // multiply 2 y = (n - p)/2 + p // multiply 2
2y = n + p // div 2 2y = n + p // div 2
y = (n + p)/2 -> y = (n + p)/2
intersection point is at
x = (n - p)/2
y = (n + p)/2
]}*) ]}*)
let point = let point =
Iter.product pos_coeffs neg_coeffs Iter.product p_slope_consts n_slope_consts
|> Iter.fold_while |> Iter.fold_while
(fun _ (p, n) -> (fun _ (p, n) ->
let i = Vec2.of_tuple ((n - p) / 2, (n + p) / 2) in let i = Vec2.of_tuple ((n - p) / 2, (n + p) / 2) in
@@ -141,6 +153,15 @@ let%expect_test "Day 15.2" =
None None
|> Option.get_exn_or "no distress beacon found :(" |> Option.get_exn_or "no distress beacon found :("
in in
Printf.printf "%i\n" ((mult * point.x) + point.y); (mult * point.x) + point.y
;;
let%expect_test "Day 15.2 example" =
Printf.printf "%i\n" @@ solve_part_2 example_lines 20 4000000;
[%expect {| 56000011 |}]
;;
let%expect_test "Day 15.2" =
Printf.printf "%i\n" @@ solve_part_2 (Utils.lines_of_input 15) 4000000 4000000;
[%expect {| 11756174628223 |}] [%expect {| 11756174628223 |}]
;; ;;
+141
View File
@@ -0,0 +1,141 @@
open Containers
let example_lines =
String.lines
{|Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II
|}
;;
type valve =
{ flow : int
; mask : int
}
let parse_valves lines =
let rooms = Hashtbl.create 100 in
lines
|> List.iter (fun line ->
let int_matches = List.map int_of_string Re.(matches (Pcre.regexp {|\d+|}) line) in
let valve_matches = Re.(matches (Pcre.regexp {|[A-Z]{2}|}) line) in
match int_matches, valve_matches with
| [ flow ], name :: tunnels -> Hashtbl.add rooms name (flow, tunnels)
| _ -> failwith "parse error");
let valves =
Hashtbl.to_list rooms
|> List.filter (fun (_, (flow, _)) -> flow > 0)
|> List.mapi (fun i (name, (flow, _)) ->
let mask = Int.(1 lsl i) in
name, { flow; mask })
in
let distances = Hashtbl.create 100 in
valves
|> List.map (fun (valve, _) -> valve)
|> List.cons "AA"
|> List.iter (fun from ->
let dist_of =
Fun.(
Utils.djikstra_hash
~get_weight:(fun _ _ -> 1)
~get_neighbors:(fun room ->
match Hashtbl.get rooms room with
| Some (_, tunnels) -> Iter.of_list tunnels
| None -> failwith "sad")
~start_nodes:[ from ]
()
%> Option.get_exn_or "big sad")
in
valves
|> List.remove_assoc ~eq:String.equal from
|> List.iter (fun (valve, _) ->
Hashtbl.replace distances (from, valve) (dist_of valve)));
let get_dist f t =
match Hashtbl.get distances (f, t) with
| Some dist -> dist
| None -> failwith @@ Printf.sprintf "cant find distance %s -> %s" f t
in
valves, get_dist
;;
let traverse
get_dist
(valves : (string * valve) list)
?(current = "AA")
?(released = 0)
?(opened = 0)
time
=
let states = Hashtbl.create 1000 in
let rec traverse' current time released opened =
Hashtbl.update
states
~f:(fun _ current ->
match current with
| Some r when r >= released -> Some r
| _ -> Some released)
~k:opened;
valves
|> List.iter (fun (name, { flow; mask }) ->
if Int.(mask land opened) = 0
then (
let dist = get_dist current name in
let time' = time - (dist + 1) in
if time' > 0
then (
let released' = released + (flow * time') in
let opened' = Int.(mask lor opened) in
traverse' name time' released' opened')))
in
traverse' current time released opened;
states
|> Iter.of_hashtbl
|> Iter.sort ~cmp:(fun (_, a_score) (_, b_score) -> b_score - a_score)
;;
let solve_part_1 lines =
let valves, get_dist = parse_valves lines in
let states = traverse get_dist valves 30 in
match states |> Iter.take 1 |> Iter.to_list with
| [ (_, score) ] -> score
| _ -> failwith "no traversals ?"
;;
let%expect_test "Day 16.1 example" =
Printf.printf "%i\n" @@ solve_part_1 example_lines;
[%expect {| 1651 |}]
;;
let%expect_test "Day 16.1" =
Printf.printf "%i\n" @@ solve_part_1 @@ Utils.lines_of_input 16;
[%expect {| 2265 |}]
;;
let solve_part_2 lines =
let valves, get_dist = parse_valves @@ lines in
let states = traverse get_dist valves 26 in
states
|> Iter.filter_map (fun (a_set, a_score) ->
match Iter.find_pred (fun (b_set, _) -> Int.(a_set land b_set) = 0) states with
| Some (_, b_score) -> Some (a_score + b_score)
| None -> None)
|> Iter.fold Int.max 0
;;
let%expect_test "Day 16.2 example" =
Printf.printf "%i\n" @@ solve_part_2 example_lines;
[%expect {| 1707 |}]
;;
(* god damn bitmasks are fast, 30x speedup from StrSet! down to 50ms now *)
let%expect_test "Day 16.2" =
Printf.printf "%i\n" @@ solve_part_2 @@ Utils.lines_of_input 16;
[%expect {| 2811 |}]
;;
+201
View File
@@ -0,0 +1,201 @@
open Containers
let cave_width = 7
let example_lines = [ ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>" ]
let dir_of_char = function
| '<' -> Vec2.left
| '>' -> Vec2.right
| _ -> failwith "oof"
;;
let next_stream_idx stream idx = (idx + 1) mod Array.length stream
(*[{
#
# # #
### # # ##
#### # ### # ##
row plus angle col square
}]*)
type shape =
| Row
| Plus
| Angle
| Col
| Square
let get_shape idx = [| Row; Plus; Angle; Col; Square |].(idx mod 5)
let shape_points shape pos =
let points =
match shape with
| Row -> [ 0, 0; 1, 0; 2, 0; 3, 0 ]
| Plus -> [ 0, 1; 1, 0; 1, 1; 1, 2; 2, 1 ]
| Angle -> [ 0, 0; 1, 0; 2, 0; 2, 1; 2, 2 ]
| Col -> [ 0, 0; 0, 1; 0, 2; 0, 3 ]
| Square -> [ 0, 0; 1, 0; 0, 1; 1, 1 ]
in
points |> List.map (fun point -> Vec2.(pos + of_tuple point))
;;
type loop_key =
{ rock : shape
; stream_idx : int
; normalized_topo : int array
}
type loop =
{ rock_idx : int
; height : int
}
type cave =
{ grid : char Grid.t
; mutable grid_topo : int array
; mutable grid_height : int
; total_rocks : int
; mutable rocks : int
; mutable stream_idx : int
; loop_cache : (loop_key, loop) Hashtbl.t
; mutable height : int
}
let init_cave max_height total_rocks =
let grid = Grid.init ~width:7 ~height:max_height (Fun.const '.') in
{ grid
; height = -1
; grid_height = -1
; rocks = 0
; stream_idx = 0
; grid_topo = Array.init cave_width (Fun.const 0)
; loop_cache = Hashtbl.create max_height
; total_rocks
}
;;
let draw_cave cave = Grid.draw cave.grid ~rev_y:true (fun _ contents -> contents)
let place_shape cave shape pos =
shape_points shape pos
|> List.iter (fun point ->
let delta = point.Vec2.y - cave.grid_height in
if delta > 0
then (
cave.height <- cave.height + delta;
cave.grid_height <- cave.grid_height + delta);
cave.grid_topo.(point.x) <- max point.y cave.grid_topo.(point.x);
Grid.set_e cave.grid point '#')
;;
let can_place_shape cave shape pos =
shape_points shape pos
|> List.fold_while
(fun _ point ->
match cave.grid.Grid.%(point) with
| Some '.' -> true, `Continue
| _ -> false, `Stop)
false
;;
let drop_shape cave stream =
let shape = get_shape cave.rocks in
let rec drop pos =
let stream_pos = Vec2.(pos + stream.(cave.stream_idx)) in
cave.stream_idx <- next_stream_idx stream cave.stream_idx;
let pos = if can_place_shape cave shape stream_pos then stream_pos else pos in
let drop_pos = Vec2.(pos + Vec2.up) in
if can_place_shape cave shape drop_pos
then drop drop_pos
else place_shape cave shape pos
in
cave.rocks <- cave.rocks + 1;
drop Vec2.{ x = 2; y = Int.(cave.grid_height + 4) }
;;
let normalize_topo topo =
let min = Array.min_exn Int.compare topo in
Array.map (fun x -> x - min) topo
;;
let rec drop_shapes cave stream =
let loop_key =
{ rock = get_shape cave.rocks
; stream_idx = cave.stream_idx
; normalized_topo = normalize_topo cave.grid_topo
}
in
let remaining_rocks cave = cave.total_rocks - cave.rocks in
let loop_rocks loop = cave.rocks - loop.rock_idx in
let loop_fits loop = loop_rocks loop < remaining_rocks cave in
match Hashtbl.get cave.loop_cache loop_key with
| Some loop when loop_fits loop ->
let loop_height = cave.height - loop.height in
cave.height <- cave.height + loop_height;
cave.rocks <- cave.rocks + loop_rocks loop;
drop_shapes cave stream
| _ when remaining_rocks cave > 0 ->
let loop = { height = cave.height; rock_idx = cave.rocks } in
Hashtbl.add cave.loop_cache loop_key loop;
drop_shape cave stream;
drop_shapes cave stream
| _ -> ()
;;
let solve remaining_rocks lines =
let stream = lines |> List.hd |> Iter.of_str |> Iter.map dir_of_char |> Iter.to_array in
let cave = init_cave 100_000 remaining_rocks in
drop_shapes cave stream;
cave.height + 1
;;
let%expect_test "Day 17.1 Example" =
Printf.printf "height: %i\n" @@ solve 2022 example_lines;
[%expect {| height: 3068 |}]
;;
let%expect_test "Day 17.1" =
Printf.printf "height: %i\n" @@ solve 2022 (Utils.lines_of_input 17);
[%expect {| height: 3227 |}]
;;
let%expect_test "Day 17.2 Example" =
Printf.printf "height: %i\n" @@ solve 1_000_000_000_000 example_lines;
[%expect {| height: 1514285714288 |}]
;;
let%expect_test "Day 17.2" =
Printf.printf "height: %i\n" @@ solve 1_000_000_000_000 (Utils.lines_of_input 17);
[%expect {| height: 1597714285698 |}]
;;
let%expect_test "Smol tower" =
let stream =
example_lines |> List.hd |> Iter.of_str |> Iter.map dir_of_char |> Iter.to_array
in
let cave = init_cave 18 8 in
drop_shapes cave stream;
Printf.printf "%s" @@ draw_cave cave;
[%expect
{|
.......
.......
.......
.....#.
.....#.
..####.
.###...
..#....
.####..
....##.
....##.
....#..
..#.#..
..#.#..
#####..
..###..
...#...
..####. |}]
;;
+121
View File
@@ -0,0 +1,121 @@
open Containers
let example_lines =
String.lines
{|2,2,2
1,2,2
3,2,2
2,1,2
2,3,2
2,2,1
2,2,3
2,2,4
2,2,6
1,2,5
3,2,5
2,1,5
2,3,5|}
;;
module Vec3 = struct
type t = int * int * int [@@deriving show, eq, ord, hash]
let directions = [ 1, 0, 0; -1, 0, 0; 0, 1, 0; 0, -1, 0; 0, 0, 1; 0, 0, -1 ]
let ( + ) (x1, y1, z1) (x2, y2, z2) = x1 + x2, y1 + y2, z1 + z2
let ( - ) (x1, y1, z1) (x2, y2, z2) = x1 - x2, y1 - y2, z1 - z2
let ( = ) = equal
let iter_region (ax, ay, az) (bx, by, bz) callback =
for z = az to bz do
for y = ay to by do
for x = ax to bx do
let p = x, y, z in
callback p
done
done
done
;;
let in_bounds (lx, ly, lz) (hx, hy, hz) (x, y, z) =
not (x < lx || x > hx || y < ly || y > hy || z < lz || z > hz)
;;
let find_bounds points =
let first = Iter.head_exn points in
let padding = 1, 1, 1 in
let min, max =
points
|> Iter.drop 1
|> Iter.fold
(fun ((lx, ly, lz), (hx, hy, hz)) (x, y, z) ->
(min lx x, min ly y, min lz z), (max hx x, max hy y, max hz z))
(first, first)
in
min - padding, max + padding
;;
end
module Vec3Set = Set.Make (Vec3)
let parse_points lines =
lines
|> List.map (fun line ->
match List.map Int.of_string_exn Re.(matches (Pcre.regexp {|\d+|}) line) with
| [ x; y; z ] -> x, y, z
| _ -> failwith "oopzi doopers")
|> Vec3Set.of_list
;;
let solve_part_1 lines =
let points = parse_points lines in
let min, max = Vec3.find_bounds @@ Vec3Set.to_iter points in
let surface_area = ref 0 in
Vec3.iter_region min max (fun point ->
if not @@ Vec3Set.mem point points
then
Vec3.directions
|> List.iter (fun dir ->
let n = Vec3.(point + dir) in
if Vec3Set.mem n points then incr surface_area));
!surface_area
;;
let%expect_test "Day 18.1 example" =
Format.printf "%i" @@ solve_part_1 example_lines;
[%expect {| 64 |}]
;;
let%expect_test "Day 18.1" =
Format.printf "%i" @@ solve_part_1 @@ Utils.lines_of_input 18;
[%expect {| 3662 |}]
;;
let solve_part_2 lines =
let points = parse_points lines in
let min, max = Vec3.find_bounds @@ Vec3Set.to_iter points in
let in_bounds = Vec3.in_bounds min max in
let surface_area = ref 0 in
let directions_iter = Iter.of_list Vec3.directions in
let get_neighbors point =
directions_iter
|> Iter.map Vec3.(fun dir -> point + dir)
|> Iter.filter (fun neighbor ->
let in_droplet = Vec3Set.mem neighbor points in
if in_droplet then incr surface_area;
(not in_droplet) && in_bounds neighbor)
in
let _ignore =
Utils.djikstra_hash ~get_weight:(fun _ _ -> 1) ~get_neighbors ~start_nodes:[ min ] ()
in
!surface_area
;;
let%expect_test "Day 18.2 example" =
Format.printf "%i" @@ solve_part_2 example_lines;
[%expect {| 58 |}]
;;
let%expect_test "Day 18.2" =
Format.printf "%i" @@ solve_part_2 @@ Utils.lines_of_input 18;
[%expect {| 2060 |}]
;;
+14 -8
View File
@@ -27,13 +27,15 @@ let at grid point =
;; ;;
let at_e (grid : 'a t) (point : Vec2.t) = let at_e (grid : 'a t) (point : Vec2.t) =
Option.get_exn_or "point out of bounds!" @@ at grid point match at grid point with
| Some point -> point
| None -> failwith @@ Format.sprintf "point %a out of bounds!" Vec2.pp point
;; ;;
let set_e grid point item = let set_e grid point item =
if in_bounds grid point if in_bounds grid point
then Array.set grid.items (idx_of_vec2 grid.width point) item then Array.set grid.items (idx_of_vec2 grid.width point) item
else failwith "point out of bounds!" else failwith (Format.sprintf "point %a out of bounds!" Vec2.pp point)
;; ;;
let ( .%() ) = at let ( .%() ) = at
@@ -82,12 +84,16 @@ let iter grid callback =
iter_region grid a b callback iter_region grid a b callback
;; ;;
let draw grid printer = let draw grid ?(rev_y = false) ?(rev_x = false) printer =
let str = ref [] in let line = ref [] in
let lines = ref [] in
iter grid (fun point -> iter grid (fun point ->
let item = grid.%(point) in let item = grid.%(point) in
let char = printer @@ Option.get_exn_or "iter is broken" item in let char = printer point (Option.get_exn_or "iter is broken" item) in
str := !str @ [ char ]; line := if rev_x then char :: !line else !line @ [ char ];
if point.x = grid.width - 1 then str := !str @ [ '\n' ]); if List.length !line = grid.width
String.of_list !str then (
lines := !lines @ [ String.of_list !line ];
line := []));
String.concat "\n" (if rev_y then List.rev !lines else !lines)
;; ;;
+1 -1
View File
@@ -11,4 +11,4 @@ val find : 'a t -> ('a -> bool) -> (Vec2.t * 'a) option
val count : 'a t -> ('a -> bool) -> int val count : 'a t -> ('a -> bool) -> int
val iter_region : 'a t -> Vec2.t -> Vec2.t -> (Vec2.t -> unit) -> unit val iter_region : 'a t -> Vec2.t -> Vec2.t -> (Vec2.t -> unit) -> unit
val iter : 'a t -> (Vec2.t -> unit) -> unit val iter : 'a t -> (Vec2.t -> unit) -> unit
val draw : 'a t -> ('a -> char) -> string val draw : 'a t -> ?rev_y:bool -> ?rev_x:bool -> (Vec2.t -> 'a -> char) -> string
+67 -1
View File
@@ -22,7 +22,7 @@ let lines_of_input day =
]} *) ]} *)
let memo f = let memo f =
let open Hashtbl in let open Hashtbl in
let cache = create 1000 in let cache = create 100000 in
let rec f_mem k = let rec f_mem k =
try find cache k with try find cache k with
| Not_found -> | Not_found ->
@@ -44,6 +44,72 @@ let%expect_test "fib memoized" =
[%expect {| 1298777728820984005 |}] [%expect {| 1298777728820984005 |}]
;; ;;
let djikstra ~eq ~get_info ~set_info ~get_weight ~get_neighbors ~goal ~start_nodes =
let seen = ref [] in
let rec djikstra' c_node =
let c_dist, _ = get_info c_node in
set_info c_node (c_dist, true);
get_neighbors c_node
|> Iter.iter (fun neighbor ->
let n_dist, n_visited = get_info neighbor in
if not n_visited
then (
let new_dist = c_dist + get_weight c_node neighbor in
if new_dist < n_dist then set_info neighbor (new_dist, n_visited);
seen := List.add_nodup ~eq neighbor !seen));
seen
:= List.fast_sort
(fun a b ->
let a_dist, _ = get_info a in
let b_dist, _ = get_info b in
Int.compare a_dist b_dist)
!seen;
match goal, !seen with
| Some goal_node, next :: _ when eq goal_node next ->
let dist, _ = get_info next in
Some dist
| None, [] -> Some 0
| _, next :: rest ->
seen := rest;
djikstra' next
| Some _, [] -> None
in
List.iter (fun node -> set_info node (0, false)) start_nodes;
match start_nodes with
| first :: rest ->
seen := rest;
djikstra' first
| _ -> failwith "start_nodes cannot be empty"
;;
let djikstra_hash
(type k)
?(hash = Hashtbl.hash)
?(eq = Stdlib.( = ))
?(slots = 100)
~get_weight
~get_neighbors
~start_nodes
()
=
let module Tbl =
CCHashtbl.Make (struct
type t = k
let equal = eq
let hash = hash
end)
in
let table = Tbl.create slots in
let get_info node = Tbl.get_or ~default:(Int.max_int, false) table node in
let set_info node info = Tbl.replace table node info in
let dist_of node = Option.(Tbl.get table node >|= fun (dist, _) -> dist) in
let _ =
djikstra ~eq ~get_info ~set_info ~get_weight ~get_neighbors ~goal:None ~start_nodes
in
dist_of
;;
module Parse = struct module Parse = struct
include Angstrom include Angstrom