solve day 14!

This commit is contained in:
ryan 2023-11-01 14:14:46 -07:00
parent ceb0f04a78
commit ceaebf895d
3 changed files with 97 additions and 219 deletions

View File

@ -10,7 +10,7 @@ type tile =
| Path_R
let char_of_tile = function
| Empty -> ' '
| Empty -> '_'
| Rock -> '#'
| Sand -> 'o'
| Start -> 'v'
@ -19,6 +19,11 @@ let char_of_tile = function
| Path_R -> '\\'
;;
let is_sand = function
| Sand -> true
| _ -> false
;;
let parse_line line =
let open Utils.Parse in
let vec = Vec2.of_tuple <$> both int (char ',' *> int) in
@ -52,10 +57,13 @@ let parse_grid lines start =
lx, hx, ly, hy)
(Int.max_int, 0, Int.max_int, 0)
in
let pad_floor = 1 in
let pad_x = 2 in
let height = 1 + hy - ly + pad_floor in
let lx = min lx (start.x - height) in
let hx = max hx (start.x + height) in
let width = 1 + hx - lx + (pad_x * 2) in
let extra = Vec2.of_tuple (lx - pad_x, ly) in
let width = hx - lx + (pad_x * 2) + 1 in
let height = hy - ly + 1 in
let start = Vec2.(start - extra) in
let open Grid in
let grid = init ~width ~height (fun _ -> Empty) in
@ -65,7 +73,7 @@ let parse_grid lines start =
grid, start
;;
let rec drop_sand grid start draw_path =
let rec drop_sand_abyss draw_path grid start =
let d = Vec2.(start + down) in
let l = Vec2.(d + left) in
let r = Vec2.(d + right) in
@ -73,242 +81,107 @@ let rec drop_sand grid start draw_path =
match grid.%(start), grid.%(l), grid.%(d), grid.%(r) with
| _, _, Some Empty, _ ->
if draw_path then grid.%(d) <- Path_D;
drop_sand grid d draw_path
drop_sand_abyss draw_path grid d
| _, Some Empty, _, _ ->
if draw_path then grid.%(l) <- Path_L;
drop_sand grid l draw_path
drop_sand_abyss draw_path grid l
| _, _, _, Some Empty ->
if draw_path then grid.%(r) <- Path_R;
drop_sand grid r draw_path
drop_sand_abyss draw_path grid r
| _, _, None, _ -> Error ()
| Some Empty, _, _, _ ->
grid.%(start) <- Sand;
Ok ()
| _, _, _, _ -> failwith "pain"
| _, _, _, _ -> failwith "oh no!"
;;
let rec drop_all_sand grid start =
match drop_sand grid start false with
| Ok () -> drop_all_sand grid start
let rec drop_sand_floor grid start =
let d = Vec2.(start + down) in
let l = Vec2.(d + left) in
let r = Vec2.(d + right) in
let open Grid in
match grid.%(start), grid.%(l), grid.%(d), grid.%(r) with
| _, _, Some Empty, _ -> drop_sand_floor grid d
| _, Some Empty, _, _ -> drop_sand_floor grid l
| _, _, _, Some Empty -> drop_sand_floor grid r
| Some Empty, _, _, _ ->
grid.%(start) <- Sand;
Ok ()
| Some Start, _, _, _ ->
grid.%(start) <- Sand;
Error ()
| _, _, _, _ -> failwith "ooooo!"
;;
let rec drop_all_sand drop grid start =
match drop grid start with
| Ok () -> drop_all_sand drop grid start
| Error _ -> ()
;;
let%expect_test "Day 14 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 start = Vec2.of_tuple (500, 0) in
let grid, start = parse_grid lines start in
let show_grid () = Printf.printf "%s" @@ Grid.draw grid char_of_tile in
show_grid ();
drop_all_sand (drop_sand_abyss false) grid start;
let _ = drop_sand_abyss true grid start in
let count = Grid.count grid is_sand in
Printf.printf "%i grains\n%s" count @@ Grid.draw grid char_of_tile;
[%expect
{|
v
# ##
# #
### #
#
#
######### |}];
drop_all_sand grid start;
let _ = drop_sand grid start true in
show_grid ();
[%expect
{|
v
|
/o
/ooo
/#ooo##
/o#ooo#
/###ooo#
| oooo#
/o ooooo#
/######### |}]
24 grains
_____________v_____________
_____________|_____________
____________/o_____________
___________/ooo____________
__________/#ooo##__________
_________/o#ooo#___________
________/###ooo#___________
________|__oooo#___________
_______/o_ooooo#___________
______/#########___________
______|____________________ |}]
;;
let%expect_test "Day 14 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 start = Vec2.of_tuple (500, 0) in
let grid, start = parse_grid lines start in
drop_all_sand drop_sand_floor grid start;
let count = Grid.count grid is_sand in
Printf.printf "%i grains\n%s" count @@ Grid.draw grid char_of_tile;
[%expect
{|
93 grains
_____________o_____________
____________ooo____________
___________ooooo___________
__________ooooooo__________
_________oo#ooo##o_________
________ooo#ooo#ooo________
_______oo###ooo#oooo_______
______oooo_oooo#ooooo______
_____oooooooooo#oooooo_____
____ooo#########ooooooo____
___ooooo_______ooooooooo___ |}]
;;
let%expect_test "Day 14.1" =
let lines = Utils.lines_of_input 14 in
let start = Vec2.of_tuple (500, 0) in
let grid, start = parse_grid lines start in
drop_all_sand grid start;
let _ = drop_sand grid start true in
Printf.printf "%s" @@ Grid.draw grid char_of_tile;
[%expect
{|
v
|
|
|
|
|
|
|
|
oo\
oooo\
oooooo\
oooooooo\
ooo#oo#ooo\
oooo#oo#oooo\
#######oo######\
# oooo #o\
# oooooo #oo\
# oooooooo #ooo\
# oooooooooo #oooo\
# oooooooooooo#ooooo\
#ooooooooooooo#oooooo\
#ooooooooooooo#ooooooo\
###############oooooooo\
oooooooooo\
oooooooooooo\
######oooooooo\
oooooooooo\
###### ######oooooo\
oooooooo\
###### ###### ######oooo\
oooooo\
###### ###### ###### ######oo\
oooo\
###### ###### ###### ###### ######\
|
|
|
|
/# #
/o# #
/#o# #
/o#o# #
/#o#o# #
|#o#o# #
|#o#o# #
|#o#o# #
|#######
|
oo\
#ooo\
#oooo\
# #ooooo\
# #ooo#o#\
# #ooo#o#|
# # #ooo#o#|
# # #o#o#o#|
# # #o#o#o#|
# # #o#o#o#|
# # #o#o#o#|
###########|
oo\
oooo\
#oooo#\
#oooo#|
#oooo#|
#########oooo##\
# oooooo#|
# ooooooo#|
# oooooooo#|
# ooooooooo#|
###############|
|
|
#oo\
# #ooo\
# # #oooo\
# # #ooo#o\
# # #ooo#o#\
# # #o#o#o#o\
# # #o#o#o#o#\
# # # #o#o#o#o#|
# # # #o#o#o#o#o\
# # # #o#o#o#o#oo\
###############ooo\
ooooo\
ooooooo\
# ooooooooo\
#############\
oo\
oooo\
######\
/o
/ooo
######/######
/o
/ooo
######/###### ######
/o
/ooo
######/###### ###### ######
/o
/ooo
######/###### ###### ###### ######
|
|
/o
/ooo
/#oooo#
/o######
/ooo
/ooooo
/#ooooo#
|#ooooo#
/o#ooooo#
/oo#ooooo#
/####ooooo#######
|# ooooooo #
|# ooooooooo #
|#ooooooooooo #
|#oooooooooooo #
|#ooooooooooooo #
|################
/o
/ooo
/ooooo
/oo#ooo#
/ooo#####
/ooooo
/ooooooo
/oo#oooo#o
/ooo#oooo#oo
/oooo#oooo#ooo
/######oooo#########
|# oooooo #
|# oooooooo #
|# oooooooooo #
/o# oooooooooooo #
/oo###################
/oooo
/oooooo
/######oo
| oooo
| oooooo
| ######oo
| oooo
/o###### ######
/ooo
/###### ###### ######
|
|
|
# oo\
# oooo\
# oooo#o\
#ooo#o#o#\
#ooo#o#o#|
#o#o#o#o#|
#o#o#o#o#|
#o#o#o#o#|
#o#o#o#o#|
#########|
oo\
oooo\
######\
/o
/ooo
######/######
/o
/ooo
######/###### ######
/o
/ooo
######/###### ###### ###### |}]
drop_all_sand (drop_sand_abyss false) grid start;
let count = Grid.count grid is_sand in
Printf.printf "%i" count;
[%expect {| 683 |}]
;;
let%expect_test "Day 14.2" =
let lines = Utils.lines_of_input 14 in
let start = Vec2.of_tuple (500, 0) in
let grid, start = parse_grid lines start in
drop_all_sand drop_sand_floor grid start;
let count = Grid.count grid is_sand in
Printf.printf "%i" count;
[%expect {| 28821 |}]
;;

View File

@ -45,6 +45,10 @@ let find (grid : 'a t) pred =
Some (vec2_of_idx ~width:grid.width ~idx, item)
;;
let count grid pred =
Array.fold (fun count item -> if pred item then count + 1 else count) 0 grid.items
;;
let init ~width ~height init =
{ width
; height

View File

@ -8,6 +8,7 @@ val ( .%()<- ) : 'a t -> Vec2.t -> 'a -> unit
val init : width:int -> height:int -> (Vec2.t -> 'a) -> 'a t
val of_lines : (char -> 'a) -> string list -> 'a t
val find : 'a t -> ('a -> bool) -> (Vec2.t * 'a) option
val count : 'a t -> ('a -> bool) -> int
val iter_region : 'a t -> Vec2.t -> Vec2.t -> (Vec2.t -> unit) -> unit
val iter : 'a t -> (Vec2.t -> unit) -> unit
val draw : 'a t -> ('a -> char) -> string