From fe93f65f6a5af8b147deb3d7d9da70ddeb68faaf Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Tue, 10 Dec 2024 11:31:02 +0000 Subject: [PATCH] Moved Grid to Aoc module. --- lib/aoc.ml | 36 +++++++++++++++++++++++++++++++++++- lib/aoc.mli | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/lib/aoc.ml b/lib/aoc.ml index 5082485..a216c19 100644 --- a/lib/aoc.ml +++ b/lib/aoc.ml @@ -21,7 +21,10 @@ let main prep parts = Printf.printf "Usage: %s \n" Sys.executable_name; exit 2 with e -> - Printf.printf "An error occured: %s\n" (Printexc.to_string e); + Printf.fprintf stderr "An error occured: %s\n" (Printexc.to_string e); + if Printexc.backtrace_status () then ( + Printf.fprintf stderr "Backtrace:\n"; + Printexc.print_backtrace stderr); exit 1 module IntPair = struct @@ -32,3 +35,34 @@ module IntPair = struct end module IntPairSet = Set.Make (IntPair) + +module Grid = struct + type t = { grid : string; width : int; height : int } + + let of_file fname = + let strs = strings_of_file fname in + let width = String.length (List.hd strs) in + let grid = List.fold_left ( ^ ) "" strs in + let height = String.length grid / width in + { grid; width; height } + + let length grid = String.length grid.grid + let pos_of_idx grid idx = (idx mod grid.width, idx / grid.width) + let idx_of_pos grid (x, y) = x + (y * grid.width) + let get_by_idx grid idx = grid.grid.[idx] + let get_by_pos grid pos = get_by_idx grid (idx_of_pos grid pos) + + let pos_is_valid grid (x, y) = + x >= 0 && x < grid.width && y >= 0 && y < grid.height + + let idx_from_opt grid = String.index_from_opt grid.grid + + let update_pos grid pos c = + let idx = idx_of_pos grid pos in + let builder = Buffer.create (length grid) in + Buffer.add_string builder (String.sub grid.grid 0 idx); + Buffer.add_char builder c; + Buffer.add_string builder + (String.sub grid.grid (idx + 1) (length grid - idx - 1)); + { grid with grid = Buffer.contents builder } +end diff --git a/lib/aoc.mli b/lib/aoc.mli index 409184e..8f50668 100644 --- a/lib/aoc.mli +++ b/lib/aoc.mli @@ -74,3 +74,50 @@ module IntPairSet : sig val add_seq : elt Seq.t -> t -> t val of_seq : elt Seq.t -> t end + +(** The [Grid] module is used to represent and manipulate a grid of characters. + Its main goals are to be non-mutable and have constant access times to + locations in the grid. + + Grid locations can be accessed by index or (col, row) position. Indicies do + not guarantee an ordering on accesses - but iterating by index from 0 to + [Grid.length grid - 1] inclusive will cover the whole grid. *) +module Grid : sig + type t + (** The type used to represent a grid *) + + val of_file : string -> t + (** [Grid.of_file fname] returns a grid loaded from the file [fname] *) + + val length : t -> int + (** [Grid.length grid] returns the length of the grid. *) + + val get_by_idx : t -> int -> char + (** [Grid.get_by_idx grid idx] returns the character at index [idx] in [grid]. + *) + + val get_by_pos : t -> int * int -> char + (** [Grid.get_by_pos grid pos] returns the character at position [pos] in + [grid]. *) + + val pos_of_idx : t -> int -> int * int + (** [Grid.pos_of_idx grid idx] returns the [(x, y)] position mapped by [idx] + in [grid]. *) + + val idx_of_pos : t -> int * int -> int + (** [Grid.pos_of_idx grid pos] returns the index corresponding to [pos] in + [grid]. *) + + val pos_is_valid : t -> int * int -> bool + (** [Grid.pos_is_valid grid pos] returns [true] if and only if [pos] is a + valid position in [grid]. *) + + val idx_from_opt : t -> int -> char -> int option + (** [Grid.idx_from_opt grid start c] returns [Some idx] where [idx] is the + first location in [grid] at or after the [start] index which is [c]. It + returns [None] if [c] does not appear. *) + + val update_pos : t -> int * int -> char -> t + (** [Grid.update_pos grid pos c] returns a grid with the character at position + [pos] changed to [c]. *) +end