Compare commits
29
Commits
421616a282
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ec58edd08 | ||
|
|
1904239ca7 | ||
|
|
46d49dc3fe | ||
|
|
950f2860df | ||
|
|
d203c9a520 | ||
|
|
8b54ae782c | ||
|
|
9f1499a1d3 | ||
|
|
490696c63d | ||
|
|
a7c039197b | ||
|
|
94f4badcc4 | ||
|
|
4e57ad4072 | ||
|
|
f2f3e497d6 | ||
|
|
2a515a5323 | ||
|
|
5c0d7867a4 | ||
|
|
1df5532c24 | ||
|
|
8db68c9baf | ||
|
|
360be1a368 | ||
|
|
ae2acb87fa | ||
|
|
c7eae53378 | ||
|
|
b9a36a476a | ||
|
|
8270ee7aa8 | ||
|
|
894e83fe12 | ||
|
|
11546bff5f | ||
|
|
d1e69ba66e | ||
|
|
2887274ad9 | ||
|
|
6758130700 | ||
|
|
ff4bb0ae89 | ||
|
|
b69f867423 | ||
|
|
a652ec69da |
No files matched your search
@@ -1,2 +1 @@
|
|||||||
profile = janestreet
|
profile = janestreet
|
||||||
version = 0.26.0
|
|
||||||
+1
-1
@@ -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;;
|
||||||
@@ -10,11 +10,11 @@ homepage: "https://github.com/username/reponame"
|
|||||||
doc: "https://url/to/documentation"
|
doc: "https://url/to/documentation"
|
||||||
bug-reports: "https://github.com/username/reponame/issues"
|
bug-reports: "https://github.com/username/reponame/issues"
|
||||||
depends: [
|
depends: [
|
||||||
"ocaml"
|
|
||||||
"dune" {>= "3.10"}
|
|
||||||
"utop"
|
"utop"
|
||||||
"ocaml-lsp-server"
|
"ocaml-lsp-server"
|
||||||
"ocamlformat"
|
"ocamlformat"
|
||||||
|
"ocaml"
|
||||||
|
"dune" {>= "3.10"}
|
||||||
"re"
|
"re"
|
||||||
"containers"
|
"containers"
|
||||||
"iter"
|
"iter"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
><<<<>>>><>>><<><<<<>>>><<>>><>>><<<<>>>><<>>>><<<>>>><<<>>>><<<>>><<<<>><>><<<<>>><><<<><><>>>><<<<><<<<>><<<>>>><<>><><>>>><<<>>><<<>>><<>>>><>>>><>><>>><<>><><<<<><>><<<>>>><<<>>><<<>><>><<<>>><<<<>>>><><<<>>><<<>>><<<<><<<<>>><<<<>>><<<>>><<<<>>><<>>><<><<<>><<<>>><<<<><<<<>>><<<><<>>>><<<>><>>><<>>><<<><<<<>>><<><<<<>>>><<>>>><<>>>><<<<>>><><<<<><>><<<>>>><<<<>><>>>><>><>><>><<<>><<<>>>><<<>><<>><<<<><<<<><<>>>><<<<><<<>>><>><<<>>><<<><<<><<<<><<><<<>>><<<<>>>><<<<><<>><<<<>>><>>><<<<><<<>>>><<><>><<<<>><<<<>>>><<<><<<<><<<<>>><<<><<>>><>>><<<<>>><<>><<<<>>><<<><<<>><<<<>>>><<<<><<><<<<>>>><>>>><<<<>>>><<<>>>><<<><<>>><>>><<<<>><<<<>>><><>><<<>>>><<<<>><<<>><<>><<<>>><<<>>>><<<<>>>><<>>>><<>>>><><<<<>><<<<>>>><<<<>>><<<<>><>><<<>>><>>>><><<>><<>>><<<>>>><>>><<>><<<>><>>><>>><><>><>><<<><<<>>>><>><<<><<<>>><<<<><<>>>><<<><<<>>>><>><<<>>>><<<>>>><>>><><>>>><>><<><<<>>>><<>>>><<<>>><<<<>>><<<>><>>>><<<<>>>><>><<>>><<<<>>>><<<<><>>>><<>><<>>>><>><<<<>>>><<<<>><<<>>>><<>><><>><<<<>><<<>>>><<<>>><<>><><<<>>>><<>><>><<>><>><<<<>><<<>>><<<<>>><<>>>><<>>><<<<>>><>><<><<<>><>>><<<>><<<<>>>><<<>>><<>>><<<>>><<<<>>>><<<<>>><<<>>><<>>>><<>>><<<>>><<><<>>>><<>>>><<><<>>><<><<<>>>><<<<><<<<>><<<>>>><>>><<<<>>><<<<>>>><<>><<<<>>>><<<><<<><<>>>><<<>>>><<<>>>><<<>><<>>><>>><<<<>>><<<<>><<<>>><<<>><<<<>>><<<<><<><>>><<<<>>><<<<>>>><>><<<<>><<<<>>>><<<<><<<>>>><>><<<<><<<<>>>><>><<><<<>>><<>>><<<<>><<<><<<><>><<>>>><<<><<<<><<<>>>><<<<>><<>><<<<>>>><><<<><<<>>>><<>>>><<>><<<<>>>><><><<<<><><<>>><<><<>>><>>><<>><><<><<>>>><<<<><<<>>>><<>><><<>>>><<<<><><<<>>>><<>>><<<><<<>>>><>><<<<>>>><>>><<><>>>><>>>><<<><>>><>>>><<<>><<<>>><<<<>>>><<>>>><<<<>>>><<><>><<<<>><<<<>>><<>>><>>>><<><<>>><>>>><<><<><<><><<<>><>><<<<>>><<<>>>><<<><<<<>><>><>>><<<<><<<>>>><<<>>><><<<<>>><<<<><<<<>>>><>><>>><<<><<>><<<><>>><<<<>><><<<<><>><<>><<>><>><<<<><<<>><>>>><<>><<<<>>><><<<>><<>><<>><>>><>>>><<><>><<<<>>><>>><<>>><<>>>><<>><<<<>>><>><<<>>><<<>>><<<<>>>><<<><<<<>><<><<<><<<>>><<><<>><>><>>><<<>>><<>><<>>><<>><<>><>><<<<>>>><<<<>>><<<>>>><<<<>>><<<>><<<>><<<<>>>><<>><<<<><<<<>><<>>><><<><<<<>>>><><>>>><<<<>>>><<<<>>>><<>><<<<>>>><<<><>><<>>>><<>>>><<<<>>>><<<>>><>><<>>>><<<>>>><<<<>>><<<<>><<<<>>>><<>>><<>>>><>>><>>>><><>><<<<>>>><<<>>>><<<>><<>>><<<<>>><>>>><<>>>><<<><>>><><<>>>><<>>>><<<>>>><<<<><<<<>>>><>>>><>><<<>>><<<>>>><<<>><<<>>><>><<>>><<><><<><<>>>><>>><<<<>><><>><>>><<<<><>>><<<>>><<<><<<<>>><<<>><<<>>><<>>><<<<><<<<><>><><<<<>>><<<>><<>><<<>><<<<>><>><>>>><<>>><<<>><<<>><<<<>><><<<<>>><<<>>>><<<<>>><<>><>><<>>><><<>>><<<>>><<<>><<>>>><<<<>><<<<>>>><<<><<><<<<>><<<<>><<<>>>><>><<<><>>>><<>>>><<><<<>>>><<<<>><<<>>>><<>>><>><<<<>>>><<<<>>><>>>><<<<><<><<>><>><>>><<<><<<<><<<<>><<<>>><<<<>><<><<<<>>>><<<>>>><<<>>>><<<<>>><<><<>><<><<<<>>>><<<><<<<>>>><<>>><<<<>><>>>><<<<>><<<>>>><<><<<<>>>><<<>><>>>><><<<>><<<><<<>>><>>>><>>><<<<><<<<>>><<>>><<<>>><<<<><<<<>>>><<>>><<<>><<>>><><<<>>>><<><>>><<>><<<>>>><<<><>><<<>>><<>>>><<<>>>><>><<><>><<>>>><<<>>>><<<<>>>><<<>>><<<>><<<<><<<<>><><<><<<>><>>><<<<>>><<<<>><<<>>><<>><<<<><<<><<<><<<>>><<<<>>><<<<>><<>>><<>><<<<>>>><<>>>><<>>>><<>><>>><>>>><<>>>><<<>>><<<<>>><>>><>>>><<<>><<>>><<>>>><<>>>><<<>>><<>>><<<><<<>><>>>><<<>><>>><<<>>><>>>><>><<>>><<<<>>><<<<>><>>><<<<>>><<<<><<<>>><><>>><<<>>><>><>>>><<>>>><<<>><<>>><<>><<<<>><<<<><>>><<>><<<<>>><<<>>><<>>>><>>>><<<><>>>><<><><>>><<>>>><<<>>>><><>><<<<>><<<>>>><<<<><<<<>>>><<<<>><>>>><<<>>>><<><<>>>><<<<>>>><<<<>>><>><>>>><>>>><>><<>>>><>>>><<>>><<<<>>>><<>>><><<>>>><<>><<<<><<><>>>><<<<>><<><<><<>><<<><<<>><<<<>>><<<<>><<>><>>><<<<>>>><<<<>>>><<<<>>><><<<<><<<<><><<<<><<<<>>>><<<<>>>><><>>><<<<><<<<><<<><><<<<>><><<<><<<<>><>>><><><<<><>>><<><<>><<<>><<<>>>><<<<>>><<>><<<<><>>><>>><<>>>><<<<>>><<<>>>><<<>>>><<<>><<<>><<<<>>><<<<>><>>><<<<><>>>><<<>><>>><<>>><<<<>><<><<<>><>>><<<>><<<<>>><<<>>>><>>><><<<><<<>>>><<>>><<><>>>><>>>><<<<>>><><><>>>><<<<>><<<<>>><<>>><<<><<<>>>><<><<<>><<<>>>><<<<>>>><>>><<<>>><><<<>><<<<>><<<>>>><>><<><><<>><<<>><<<>>><<<<>>>><<<><<<<>><<<<>>>><<<<>>>><<><<<<>>><<<<>><<<<>><<<>><<<<>>><<>>>><<>>><>><<>>>><>>><>>><<<><>>>><<<>>><<<<><<<<>>><<><><>>>><<>>>><<>>>><<<<>>>><<><<><<<>>><<<>>>><<><<<><<>>><<<><<<>>>><<<<>>><<>>>><<>><><<<><<>><<>>><<<<>><>><<<>><<<<>><<<<><<>>><<><<<<>>>><<<>><<<<>><<>>>><>>>><>>><>>>><<<>>><<<>>>><<>>>><>><>><<<>><<<>>><<>>><<<<>>><<<<>>><<>>>><>>><>><<<<>>>><<>>>><<>>>><<<<>>>><>>>><><>>><<>>>><<<<><<>>>><<<<>><<<<>>>><<>><<<<><<<<>>><<<<>><<>>>><<<>>>><<<><>><<<><<>>><<<<>><<<>>><><<<<>><<<<>><>>><<<<>>><<<<>>>><>>>><<>>>><<>>><>>>><<<<>>><<>><<<><<><<<>>>><<<>>>><<<<><<>>><>><<<<><<<>>><>><><<<><<>>>><>>>><>><<>>><<>>>><<>>>><<<<>><<>><><<>>><<>><<>><<>>><>><<<<>>>><<>>>><<<<>>><<>><><<<><>><<<>><>>><>><<>>><><>>><<>>>><<<>>><<<<>>><<<>><<>><<<<>>><<<><<<>><<<<><<>><>><<<<>><<>>>><<<>><<<>>>><<<<>>>><<<<>><<>>><<<>>><<<>>>><<<<>>><<<<>>>><>><<<<>>>><<>>><><<>>>><<<<>>>><<<<>>>><>><<>><<<<><<<<>>><><>>><<<<>>><<><>>>><<<<><<<>>>><>>>><<<>>>><<<>>>><<>>><<>>><<<<><<<>><>>><<<><<<>>><Line truncated
|
||||||
+2025
File diff suppressed because it is too large.
Load diff
+63
-45
@@ -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 |}]
|
||||||
|
;;
|
||||||
+14
-9
@@ -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'
|
||||||
@@ -43,9 +43,9 @@ let draw_rocks grid points =
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
let parse_grid lines start =
|
let parse_grid lines start =
|
||||||
let points = List.map parse_line lines in
|
let points = Iter.map Fun.(parse_line %> Iter.of_list) lines in
|
||||||
let Vec2.{ x = lx; y = ly }, Vec2.{ x = hx; y = hy } =
|
let Vec2.{ x = lx; y = ly }, Vec2.{ x = hx; y = hy } =
|
||||||
points |> List.flatten |> List.append [ start ] |> Vec2.bounds 0
|
points |> Iter.flatten |> Iter.cons start |> Vec2.find_bounds 0
|
||||||
in
|
in
|
||||||
let pad_floor = 1 in
|
let pad_floor = 1 in
|
||||||
let pad_x = 2 in
|
let pad_x = 2 in
|
||||||
@@ -58,8 +58,9 @@ let parse_grid lines start =
|
|||||||
let open Grid in
|
let open Grid in
|
||||||
let grid = init ~width ~height (fun _ -> Empty) in
|
let grid = init ~width ~height (fun _ -> Empty) in
|
||||||
grid.%(start) <- Start;
|
grid.%(start) <- Start;
|
||||||
points
|
Iter.iter
|
||||||
|> List.iter Fun.(List.map (fun point -> Vec2.(point - extra)) %> draw_rocks grid);
|
Fun.(Iter.map (fun point -> Vec2.(point - extra)) %> Iter.to_list %> draw_rocks grid)
|
||||||
|
points;
|
||||||
grid, start
|
grid, start
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@@ -118,7 +119,9 @@ let rec drop_all_sand drop grid start =
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
let%expect_test "Day 14.1 example" =
|
let%expect_test "Day 14.1 example" =
|
||||||
let lines = [ "498,4 -> 498,6 -> 496,6"; "503,4 -> 502,4 -> 502,9 -> 494,9" ] in
|
let lines =
|
||||||
|
Iter.of_list [ "498,4 -> 498,6 -> 496,6"; "503,4 -> 502,4 -> 502,9 -> 494,9" ]
|
||||||
|
in
|
||||||
let start = Vec2.of_tuple (500, 0) in
|
let start = Vec2.of_tuple (500, 0) in
|
||||||
let grid, start = parse_grid lines start in
|
let grid, start = parse_grid lines start in
|
||||||
drop_all_sand (drop_sand_abyss false) grid start;
|
drop_all_sand (drop_sand_abyss false) grid start;
|
||||||
@@ -142,7 +145,9 @@ let%expect_test "Day 14.1 example" =
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
let%expect_test "Day 14.2 example" =
|
let%expect_test "Day 14.2 example" =
|
||||||
let lines = [ "498,4 -> 498,6 -> 496,6"; "503,4 -> 502,4 -> 502,9 -> 494,9" ] in
|
let lines =
|
||||||
|
Iter.of_list [ "498,4 -> 498,6 -> 496,6"; "503,4 -> 502,4 -> 502,9 -> 494,9" ]
|
||||||
|
in
|
||||||
let start = Vec2.of_tuple (500, 0) in
|
let start = Vec2.of_tuple (500, 0) in
|
||||||
let grid, start = parse_grid lines start in
|
let grid, start = parse_grid lines start in
|
||||||
drop_all_sand drop_sand_floor grid start;
|
drop_all_sand drop_sand_floor grid start;
|
||||||
@@ -165,7 +170,7 @@ let%expect_test "Day 14.2 example" =
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
let%expect_test "Day 14.1" =
|
let%expect_test "Day 14.1" =
|
||||||
let lines = Utils.lines_of_input 14 in
|
let lines = Iter.of_list @@ Utils.lines_of_input 14 in
|
||||||
let start = Vec2.of_tuple (500, 0) in
|
let start = Vec2.of_tuple (500, 0) in
|
||||||
let grid, start = parse_grid lines start in
|
let grid, start = parse_grid lines start in
|
||||||
drop_all_sand (drop_sand_abyss false) grid start;
|
drop_all_sand (drop_sand_abyss false) grid start;
|
||||||
@@ -175,7 +180,7 @@ let%expect_test "Day 14.1" =
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
let%expect_test "Day 14.2" =
|
let%expect_test "Day 14.2" =
|
||||||
let lines = Utils.lines_of_input 14 in
|
let lines = Iter.of_list @@ Utils.lines_of_input 14 in
|
||||||
let start = Vec2.of_tuple (500, 0) in
|
let start = Vec2.of_tuple (500, 0) in
|
||||||
let grid, start = parse_grid lines start in
|
let grid, start = parse_grid lines start in
|
||||||
drop_all_sand drop_sand_floor grid start;
|
drop_all_sand drop_sand_floor grid start;
|
||||||
|
|||||||
+119
-117
@@ -1,31 +1,5 @@
|
|||||||
open Containers
|
open Containers
|
||||||
|
|
||||||
type sensor =
|
|
||||||
{ pos : Vec2.t
|
|
||||||
; beacon : Vec2.t
|
|
||||||
; dist : int
|
|
||||||
}
|
|
||||||
[@@deriving show { with_path = false }]
|
|
||||||
|
|
||||||
let taxicab_dist a b =
|
|
||||||
let x, y = Vec2.(abs (a - b) |> to_tuple) in
|
|
||||||
x + y
|
|
||||||
;;
|
|
||||||
|
|
||||||
let parse_sensor line =
|
|
||||||
let open Utils.Parse in
|
|
||||||
let parse =
|
|
||||||
many1 (not_int *> int)
|
|
||||||
>>= function
|
|
||||||
| [ sx; sy; bx; by ] ->
|
|
||||||
let pos = Vec2.of_tuple (sx, sy) in
|
|
||||||
let beacon = Vec2.of_tuple (bx, by) in
|
|
||||||
return { pos; beacon; dist = taxicab_dist pos beacon }
|
|
||||||
| _ -> failwith "should be four ints"
|
|
||||||
in
|
|
||||||
Result.get_or_failwith @@ parse_string ~consume:All parse line
|
|
||||||
;;
|
|
||||||
|
|
||||||
let example_lines =
|
let example_lines =
|
||||||
[ "Sensor at x=2, y=18: closest beacon is at x=-2, y=15"
|
[ "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=9, y=16: closest beacon is at x=10, y=16"
|
||||||
@@ -44,17 +18,29 @@ let example_lines =
|
|||||||
]
|
]
|
||||||
;;
|
;;
|
||||||
|
|
||||||
let bounds sensors =
|
type sensor =
|
||||||
let max_dist = sensors |> List.fold_left (fun acc s -> max acc s.dist) 0 in
|
{ pos : Vec2.t
|
||||||
sensors
|
; beacon : Vec2.t
|
||||||
|> List.flat_map (fun sensor -> [ sensor.pos; sensor.beacon ])
|
; dist : int
|
||||||
|> Vec2.bounds max_dist
|
}
|
||||||
|
[@@deriving show { with_path = false }]
|
||||||
|
|
||||||
|
let taxicab_dist a b =
|
||||||
|
let x, y = Vec2.(abs (a - b) |> to_tuple) in
|
||||||
|
x + y
|
||||||
|
;;
|
||||||
|
|
||||||
|
let parse_sensor line =
|
||||||
|
match List.map int_of_string Re.(matches (Pcre.regexp {|-?\d+|}) line) with
|
||||||
|
| [ sx; sy; bx; by ] ->
|
||||||
|
let pos, beacon = Vec2.(of_tuple (sx, sy), of_tuple (bx, by)) in
|
||||||
|
{ pos; beacon; dist = taxicab_dist pos beacon }
|
||||||
|
| _ -> failwith "parse error"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
let could_be_beacon sensors ignore_known pos =
|
let could_be_beacon sensors ignore_known pos =
|
||||||
let open Iter in
|
sensors
|
||||||
of_list sensors
|
|> Iter.fold_while
|
||||||
|> fold_while
|
|
||||||
(fun _ s ->
|
(fun _ s ->
|
||||||
let d = taxicab_dist pos s.pos in
|
let d = taxicab_dist pos s.pos in
|
||||||
if d <= s.dist && (ignore_known || not Vec2.(pos = s.beacon))
|
if d <= s.dist && (ignore_known || not Vec2.(pos = s.beacon))
|
||||||
@@ -63,95 +49,102 @@ let could_be_beacon sensors ignore_known pos =
|
|||||||
true
|
true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
(* let%expect_test "Day 15.1" = *)
|
(*{[
|
||||||
(* let sensors = Utils.lines_of_input 15 |> List.map parse_sensor in *)
|
equation for line
|
||||||
(* let scan_row = 2000000 in *)
|
y = m*x + c
|
||||||
(* let Vec2.{ x = lx; _ }, Vec2.{ x = hx; _ } = bounds sensors in *)
|
|
||||||
(* Vec2.fold_region *)
|
|
||||||
(* Vec2.{ x = lx; y = scan_row } *)
|
|
||||||
(* Vec2.{ x = hx; y = scan_row } *)
|
|
||||||
(* (fun acc pos -> if could_be_beacon sensors false pos then acc else acc + 1) *)
|
|
||||||
(* 0 *)
|
|
||||||
(* |> Printf.printf "%i\n"; *)
|
|
||||||
(* [%expect {| 5525990 |}] *)
|
|
||||||
(* ;; *)
|
|
||||||
|
|
||||||
(* module VecTbl = Hashtbl.Make (Vec2) *)
|
beacon range boundaries are made up of four lines:
|
||||||
|
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
|
||||||
|
|
||||||
(* let points_on_border tbl sensor = *)
|
to find the constant given a slope, plug a point into
|
||||||
(* let points = ref [] in *)
|
c = y - m*x
|
||||||
(* let dist = sensor.dist + 1 in *)
|
|
||||||
(* for d1 = 0 to dist do *)
|
|
||||||
(* let d2 = dist - d1 in *)
|
|
||||||
(* let open Vec2 in *)
|
|
||||||
(* let p1 = of_tuple (d1, d2) in *)
|
|
||||||
(* let p2 = of_tuple (d1, Int.(-d2)) in *)
|
|
||||||
(* let new_points = *)
|
|
||||||
(* [ sensor.pos + p1; sensor.pos - p1; sensor.pos + p2; sensor.pos - p2 ] *)
|
|
||||||
(* |> List.fold_left *)
|
|
||||||
(* (fun acc point -> *)
|
|
||||||
(* match VecTbl.find_opt tbl point with *)
|
|
||||||
(* | Some false -> acc *)
|
|
||||||
(* | Some true -> *)
|
|
||||||
(* VecTbl.replace tbl point false; *)
|
|
||||||
(* point :: acc *)
|
|
||||||
(* | None -> *)
|
|
||||||
(* VecTbl.add tbl point true; *)
|
|
||||||
(* acc) *)
|
|
||||||
(* [] *)
|
|
||||||
(* in *)
|
|
||||||
(* points := !points @ new_points *)
|
|
||||||
(* done; *)
|
|
||||||
(* !points *)
|
|
||||||
(* ;; *)
|
|
||||||
|
|
||||||
(* let%expect_test "Day 15.2 brute force" = *)
|
constants are stored separately for boundaries with positive and negative
|
||||||
(* let sensors = Utils.lines_of_input 15 |> List.map parse_sensor in *)
|
slope so that they can be handled separately
|
||||||
(* let mult = 4000000 in *)
|
p1 = y - bx - dist - 1
|
||||||
(* let range = mult in *)
|
p2 = y - bx + dist + 1
|
||||||
(* let in_bounds = Vec2.(in_bounds origin @@ of_tuple (range, range)) in *)
|
n1 = y + bx + dist + 1
|
||||||
(* let tbl = VecTbl.create (range * 10) in *)
|
n2 = y + bx - dist - 1
|
||||||
(* let point = *)
|
]}*)
|
||||||
(* sensors *)
|
let get_consts sensors extra =
|
||||||
(* |> Iter.of_list *)
|
sensors
|
||||||
(* |> Iter.flat_map_l @@ points_on_border tbl *)
|
|> Iter.fold
|
||||||
(* |> Iter.fold_while *)
|
(fun (p_slope_consts, n_slope_consts) { pos; beacon = _; dist } ->
|
||||||
(* (fun _ v -> *)
|
let p1 = pos.y - pos.x + dist + extra in
|
||||||
(* if in_bounds v && could_be_beacon sensors true v *)
|
let p2 = pos.y - pos.x - dist - extra in
|
||||||
(* then Some v, `Stop *)
|
let n1 = pos.y + pos.x + dist + extra in
|
||||||
(* else None, `Continue) *)
|
let n2 = pos.y + pos.x - dist - extra in
|
||||||
(* None *)
|
Iter.(
|
||||||
(* |> Option.get_exn_or "fucc :(" *)
|
( append p_slope_consts (of_list [ p1; p2 ])
|
||||||
(* in *)
|
, append n_slope_consts (of_list [ n1; n2 ]) )))
|
||||||
(* Printf.printf "%i\n" ((mult * point.x) + point.y); *)
|
(Iter.empty, Iter.empty)
|
||||||
(* [%expect {| 11756174628223 |}] *)
|
;;
|
||||||
(* ;; *)
|
|
||||||
|
|
||||||
module IntSet = Set.Make (Int)
|
let solve_part_1 lines scan_y =
|
||||||
|
let sensors = lines |> Iter.of_list |> Iter.map parse_sensor in
|
||||||
|
let p_slope_consts, n_slope_consts = get_consts sensors 0 in
|
||||||
|
(*{[
|
||||||
|
for a known y to intersect with a positive slope boundary:
|
||||||
|
y = x + p
|
||||||
|
x = y - p
|
||||||
|
|
||||||
let%expect_test "Day 15.2" =
|
and for a negative slope boundary:
|
||||||
let sensors = Utils.lines_of_input 15 |> List.map parse_sensor in
|
y = -x + n
|
||||||
let mult = 4000000 in
|
x = n - y
|
||||||
let range = mult in
|
]}*)
|
||||||
let in_bounds = Vec2.(in_bounds origin @@ of_tuple (range, range)) in
|
let intersection_xs =
|
||||||
let pos_coeffs, neg_coeffs =
|
Iter.append
|
||||||
sensors
|
(Iter.map (fun p -> scan_y - p) p_slope_consts)
|
||||||
|> Iter.of_list
|
(Iter.map (fun n -> n - scan_y) n_slope_consts)
|
||||||
|> Iter.fold
|
|> Iter.sort_uniq ~cmp:Int.compare
|
||||||
(fun (pos_coeffs, neg_coeffs) { pos; beacon = _; dist } ->
|
|
||||||
let p1 = pos.y - pos.x + dist + 1 in
|
|
||||||
let p2 = pos.y - pos.x - dist - 1 in
|
|
||||||
let n1 = pos.y + pos.x + dist + 1 in
|
|
||||||
let n2 = pos.y + pos.x - dist - 1 in
|
|
||||||
Iter.(
|
|
||||||
( append pos_coeffs (of_list [ p1; p2 ])
|
|
||||||
, append neg_coeffs (of_list [ n1; n2 ]) )))
|
|
||||||
(Iter.empty, Iter.empty)
|
|
||||||
in
|
in
|
||||||
|
let check x = could_be_beacon sensors false @@ Vec2.of_tuple (x, scan_y) in
|
||||||
|
let rec count_not_beacons count xs =
|
||||||
|
match xs with
|
||||||
|
| x :: next :: rest ->
|
||||||
|
(* if there is a region [x+1, next), the value of check
|
||||||
|
is the same for each point within it. intersection points
|
||||||
|
must be checked separately from the regions between them *)
|
||||||
|
let intersection = if check x then 0 else 1 in
|
||||||
|
let region = if x + 1 < next && check (x + 1) then 0 else next - (x + 1) in
|
||||||
|
count_not_beacons (count + intersection + region) (next :: rest)
|
||||||
|
| _ -> count
|
||||||
|
in
|
||||||
|
count_not_beacons 0 @@ Iter.to_list intersection_xs
|
||||||
|
;;
|
||||||
|
|
||||||
|
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 |}]
|
||||||
|
;;
|
||||||
|
|
||||||
|
let solve_part_2 lines range mult =
|
||||||
|
let sensors = lines |> Iter.of_list |> Iter.map parse_sensor in
|
||||||
|
let in_bounds = Vec2.(in_bounds origin @@ of_tuple (range, range)) in
|
||||||
|
let p_slope_consts, n_slope_consts = get_consts sensors 1 in
|
||||||
|
(*{[
|
||||||
|
boundaries only itersect if they have opposite slope.
|
||||||
|
to find the intersection, set equations to be equal and solve.
|
||||||
|
y = x + p
|
||||||
|
y = -x + n // set equal
|
||||||
|
x + p = -x + n // add x and subtract p
|
||||||
|
2x = n - p // divide 2
|
||||||
|
-> x = (n - p)/2 // substitute x into original
|
||||||
|
y = (n - p)/2 + p // multiply 2
|
||||||
|
2y = n + p // div 2
|
||||||
|
-> y = (n + p)/2
|
||||||
|
]}*)
|
||||||
let point =
|
let point =
|
||||||
let open Iter in
|
Iter.product p_slope_consts n_slope_consts
|
||||||
product pos_coeffs neg_coeffs
|
|> Iter.fold_while
|
||||||
|> 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
|
||||||
if in_bounds i && could_be_beacon sensors true i
|
if in_bounds i && could_be_beacon sensors true i
|
||||||
@@ -160,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
+100
@@ -10,6 +10,106 @@ let lines_of_input day =
|
|||||||
IO.(with_in path read_lines_l)
|
IO.(with_in path read_lines_l)
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
(** [f] in [memo f] should be a function that makes recursive calls
|
||||||
|
via the memoized function passed as its first argument. ie:
|
||||||
|
{[
|
||||||
|
let fib_m =
|
||||||
|
memo (fun self x ->
|
||||||
|
match x with
|
||||||
|
| 0 | 1 -> 1
|
||||||
|
| x -> self (x - 1) + self (x - 2))
|
||||||
|
;;
|
||||||
|
]} *)
|
||||||
|
let memo f =
|
||||||
|
let open Hashtbl in
|
||||||
|
let cache = create 100000 in
|
||||||
|
let rec f_mem k =
|
||||||
|
try find cache k with
|
||||||
|
| Not_found ->
|
||||||
|
let v = f f_mem k in
|
||||||
|
add cache k v;
|
||||||
|
v
|
||||||
|
in
|
||||||
|
f_mem
|
||||||
|
;;
|
||||||
|
|
||||||
|
let%expect_test "fib memoized" =
|
||||||
|
let fib_m =
|
||||||
|
memo (fun fib_m x ->
|
||||||
|
match x with
|
||||||
|
| 0 | 1 -> 1
|
||||||
|
| x -> fib_m (x - 1) + fib_m (x - 2))
|
||||||
|
in
|
||||||
|
Printf.printf "%i\n" @@ fib_m 100;
|
||||||
|
[%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
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -35,10 +35,10 @@ let fold_region a b callback init =
|
|||||||
!acc
|
!acc
|
||||||
;;
|
;;
|
||||||
|
|
||||||
let bounds padding points =
|
let find_bounds padding points =
|
||||||
let lx, hx, ly, hy =
|
let lx, hx, ly, hy =
|
||||||
points
|
points
|
||||||
|> List.fold_left
|
|> Iter.fold
|
||||||
(fun (lx, hx, ly, hy) { x; y } ->
|
(fun (lx, hx, ly, hy) { x; y } ->
|
||||||
let lx = min lx x in
|
let lx = min lx x in
|
||||||
let hx = max hx x in
|
let hx = max hx x in
|
||||||
|
|||||||
+1
-1
@@ -20,5 +20,5 @@ val ( = ) : t -> t -> bool
|
|||||||
val abs : t -> t
|
val abs : t -> t
|
||||||
val iter_region : t -> t -> (t -> unit) -> unit
|
val iter_region : t -> t -> (t -> unit) -> unit
|
||||||
val fold_region : t -> t -> ('a -> t -> 'a) -> 'a -> 'a
|
val fold_region : t -> t -> ('a -> t -> 'a) -> 'a -> 'a
|
||||||
val bounds : int -> t list -> t * t
|
val find_bounds : int -> t Iter.t -> t * t
|
||||||
val in_bounds : t -> t -> t -> bool
|
val in_bounds : t -> t -> t -> bool
|
||||||
Reference in new issue
Block a user