Tidy up 2024 day 15
This commit is contained in:
		| @@ -1,5 +1,9 @@ | |||||||
| type grid = { grid : char array; width : int; height : int } | type grid = { grid : char array; width : int } | ||||||
|  | (** Grid type. Not our normal type as we want to use it in a mutable way. *) | ||||||
|  |  | ||||||
|  | (** [grid_map fn strs] Returns a grid built up from the list of strings [strs]. | ||||||
|  |     [fn] takes a single string of all map characters and returns a string with | ||||||
|  |     the appropriate replacements done. *) | ||||||
| let grid_make posmap_fn strs = | let grid_make posmap_fn strs = | ||||||
|   let grid = |   let grid = | ||||||
|     List.fold_left String.cat "" strs |     List.fold_left String.cat "" strs | ||||||
| @@ -7,9 +11,9 @@ let grid_make posmap_fn strs = | |||||||
|   in |   in | ||||||
|   let height = List.length strs in |   let height = List.length strs in | ||||||
|   let width = Array.length grid / height in |   let width = Array.length grid / height in | ||||||
|   Printf.printf "width %d height %d \n" width height; |   { grid; width } | ||||||
|   { grid; width; height } |  | ||||||
|  |  | ||||||
|  | (** [grid_print grid] prints [grid] to standard output. *) | ||||||
| let[@warning "-32"] grid_print grid = | let[@warning "-32"] grid_print grid = | ||||||
|   Array.iteri |   Array.iteri | ||||||
|     (fun i c -> |     (fun i c -> | ||||||
| @@ -17,11 +21,16 @@ let[@warning "-32"] grid_print grid = | |||||||
|       if i mod grid.width = grid.width - 1 then print_newline ()) |       if i mod grid.width = grid.width - 1 then print_newline ()) | ||||||
|     grid.grid |     grid.grid | ||||||
|  |  | ||||||
| let find_start_idx grid = | (** [find_robot_idx grid] returns the index of the robot in grid. *) | ||||||
|  | let find_robot_idx grid = | ||||||
|   match Array.find_index (( = ) '@') grid.grid with |   match Array.find_index (( = ) '@') grid.grid with | ||||||
|   | None -> failwith "find_start_idx" |   | None -> failwith "find_robot_idx" | ||||||
|   | Some x -> x |   | Some x -> x | ||||||
|  |  | ||||||
|  | (** [instrs_of_file fname] reads from the file [fname] and returns a | ||||||
|  |     [(grid, instrs)] pair. [grid] is a list of strings describing the initial | ||||||
|  |     grid state. [instrs] is a list of characters giving movement instructions. | ||||||
|  | *) | ||||||
| let instrs_of_file fname = | let instrs_of_file fname = | ||||||
|   let strs = Aoc.strings_of_file fname in |   let strs = Aoc.strings_of_file fname in | ||||||
|   let rec impl acc = function |   let rec impl acc = function | ||||||
| @@ -32,19 +41,29 @@ let instrs_of_file fname = | |||||||
|   let grid, moves = impl [] strs in |   let grid, moves = impl [] strs in | ||||||
|   (grid, List.fold_left String.cat "" moves |> String.to_seq |> List.of_seq) |   (grid, List.fold_left String.cat "" moves |> String.to_seq |> List.of_seq) | ||||||
|  |  | ||||||
| let rec move_robot_x grid i di = | (** [move_x grid i di] moves the object in [grid] at [i] to [i + di] if | ||||||
|  |     possible, returning the new location of the object (either [i] or [i + di]). | ||||||
|  |     This assumes a horizontal movement of one step. *) | ||||||
|  | let rec move_x grid i di = | ||||||
|  |   assert (di == -1 || di == 1); | ||||||
|  |   assert (i >= 0 && i <= Array.length grid.grid); | ||||||
|   match grid.grid.(i + di) with |   match grid.grid.(i + di) with | ||||||
|   | '#' -> i |   | '#' -> i | ||||||
|   | 'O' | '[' | ']' -> |   | 'O' | '[' | ']' -> | ||||||
|       if move_robot_x grid (i + di) di = i + di then i |       if move_x grid (i + di) di = i + di then i else move_x grid i di | ||||||
|       else move_robot_x grid i di |  | ||||||
|   | '.' -> |   | '.' -> | ||||||
|       grid.grid.(i + di) <- grid.grid.(i); |       grid.grid.(i + di) <- grid.grid.(i); | ||||||
|       grid.grid.(i) <- '.'; |       grid.grid.(i) <- '.'; | ||||||
|       i + di |       i + di | ||||||
|   | _ -> failwith "move_robot_x" |   | _ -> failwith "move_x" | ||||||
|  |  | ||||||
|  | (** [can_move_y grid i di] returns true if and only if it is possible to move | ||||||
|  |     whatever is at [i] to [i + di] in [grid]. If [i + di] is full it recursively | ||||||
|  |     checks to see if that can be moved as well. [di] must be a vertical | ||||||
|  |     movement. *) | ||||||
| let rec can_move_y grid i di = | let rec can_move_y grid i di = | ||||||
|  |   assert (i >= 0 && i < Array.length grid.grid); | ||||||
|  |   assert (di = grid.width || di = -grid.width); | ||||||
|   match grid.grid.(i + di) with |   match grid.grid.(i + di) with | ||||||
|   | '#' -> false |   | '#' -> false | ||||||
|   | '.' -> true |   | '.' -> true | ||||||
| @@ -53,10 +72,15 @@ let rec can_move_y grid i di = | |||||||
|   | ']' -> can_move_y grid (i + di - 1) di && can_move_y grid (i + di) di |   | ']' -> can_move_y grid (i + di - 1) di && can_move_y grid (i + di) di | ||||||
|   | _ -> failwith "can_move_y" |   | _ -> failwith "can_move_y" | ||||||
|  |  | ||||||
| let move_robot_y grid i di = | (** [move_x grid i di] moves the object in [grid] at [i] to [i + di] if | ||||||
|  |     possible, returning the new location of the object (either [i] or [i + di]). | ||||||
|  |     This assumes a vertical movement of one step. *) | ||||||
|  | let move_y grid i di = | ||||||
|  |   assert (i >= 0 && i < Array.length grid.grid); | ||||||
|  |   assert (di = grid.width || di = -grid.width); | ||||||
|   let rec do_move i = |   let rec do_move i = | ||||||
|     match grid.grid.(i + di) with |     match grid.grid.(i + di) with | ||||||
|     | '#' -> failwith "move_robot_y.do_move #" |     | '#' -> failwith "move_y.do_move #" | ||||||
|     | '.' -> |     | '.' -> | ||||||
|         grid.grid.(i + di) <- grid.grid.(i); |         grid.grid.(i + di) <- grid.grid.(i); | ||||||
|         grid.grid.(i) <- '.' |         grid.grid.(i) <- '.' | ||||||
| @@ -71,27 +95,31 @@ let move_robot_y grid i di = | |||||||
|         do_move (i + di - 1); |         do_move (i + di - 1); | ||||||
|         do_move (i + di); |         do_move (i + di); | ||||||
|         do_move i |         do_move i | ||||||
|     | _ -> failwith "move_robot_y.do_move" |     | _ -> failwith "move_y.do_move" | ||||||
|   in |   in | ||||||
|   if can_move_y grid i di then ( |   if can_move_y grid i di then ( | ||||||
|     do_move i; |     do_move i; | ||||||
|     i + di) |     i + di) | ||||||
|   else i |   else i | ||||||
|  |  | ||||||
|  | (** [process_move grid robot dir] attempts to move robot at idx [robot] in | ||||||
|  |     [grid] in direction. Returns location of robot after attempt. *) | ||||||
| let process_move grid robot dir = | let process_move grid robot dir = | ||||||
|   (*grid_print grid; |  | ||||||
|   Printf.printf "\nMove: %c\n" dir;*) |  | ||||||
|   match dir with |   match dir with | ||||||
|   | '^' -> move_robot_y grid robot ~-(grid.width) |   | '^' -> move_y grid robot (-grid.width) | ||||||
|   | 'v' -> move_robot_y grid robot grid.width |   | 'v' -> move_y grid robot grid.width | ||||||
|   | '<' -> move_robot_x grid robot ~-1 |   | '<' -> move_x grid robot ~-1 | ||||||
|   | '>' -> move_robot_x grid robot 1 |   | '>' -> move_x grid robot 1 | ||||||
|   | _ -> failwith "process_move" |   | _ -> failwith "process_move" | ||||||
|  |  | ||||||
|  | (** [process_moves grid robot lst] Attempts each move in [lst] in turn given a | ||||||
|  |     [grid] and initial starting position of the robot [robot]. Returns the | ||||||
|  |     [grid]. *) | ||||||
| let rec process_moves grid robot = function | let rec process_moves grid robot = function | ||||||
|   | [] -> grid |   | [] -> () | ||||||
|   | h :: t -> process_moves grid (process_move grid robot h) t |   | h :: t -> process_moves grid (process_move grid robot h) t | ||||||
|  |  | ||||||
|  | (** [calc_score grid] returns the score for [grid]. *) | ||||||
| let calc_score grid = | let calc_score grid = | ||||||
|   Array.mapi |   Array.mapi | ||||||
|     (fun idx c -> |     (fun idx c -> | ||||||
| @@ -101,6 +129,8 @@ let calc_score grid = | |||||||
|     grid.grid |     grid.grid | ||||||
|   |> Array.fold_left ( + ) 0 |   |> Array.fold_left ( + ) 0 | ||||||
|  |  | ||||||
|  | (** [expand_grid str] given an input [str] returns the output grid string for | ||||||
|  |     part 2. *) | ||||||
| let expand_grid str = | let expand_grid str = | ||||||
|   let b = Buffer.create (String.length str * 2) in |   let b = Buffer.create (String.length str * 2) in | ||||||
|   let add_c = function |   let add_c = function | ||||||
| @@ -113,10 +143,12 @@ let expand_grid str = | |||||||
|   String.iter add_c str; |   String.iter add_c str; | ||||||
|   Buffer.contents b |   Buffer.contents b | ||||||
|  |  | ||||||
|  | (** [part posmap_fn (grid, moves)] executes the [moves] in [grid] having first | ||||||
|  |     applied [posmap_fn] to grid. *) | ||||||
| let part posmap_fn (grid, moves) = | let part posmap_fn (grid, moves) = | ||||||
|   let grid = grid_make posmap_fn grid in |   let grid = grid_make posmap_fn grid in | ||||||
|   let robot = find_start_idx grid in |   let robot = find_robot_idx grid in | ||||||
|   let _ = process_moves grid robot moves in |   process_moves grid robot moves; | ||||||
|   (*grid_print grid;*) |   (*grid_print grid;*) | ||||||
|   calc_score grid |   calc_score grid | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user