104 lines
2.9 KiB
OCaml
104 lines
2.9 KiB
OCaml
let ints_of_string ?(sep = " ") s =
|
|
List.map int_of_string (Str.split (Str.regexp sep) s)
|
|
|
|
let distance1 a b = abs (a - b)
|
|
|
|
let strings_of_file fname =
|
|
In_channel.with_open_text fname In_channel.input_lines
|
|
|
|
let string_of_file fname =
|
|
match In_channel.with_open_text fname In_channel.input_line with
|
|
| Some x -> x
|
|
| None -> failwith "Aoc.string_of_file"
|
|
|
|
let main prep parts =
|
|
try
|
|
match Sys.argv with
|
|
| [| _; fname |] ->
|
|
let lines = prep fname in
|
|
let do_part i (fmt, fn) =
|
|
Printf.printf "Part %d = %s\n" (i + 1) (fmt (fn lines));
|
|
flush stdout
|
|
in
|
|
List.iteri do_part parts;
|
|
exit 0
|
|
| _ ->
|
|
Printf.printf "Usage: %s <fname>\n" Sys.executable_name;
|
|
exit 2
|
|
with 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
|
|
type t = int * int
|
|
|
|
let compare (x, y) (x', y') =
|
|
match compare y y' with 0 -> compare x x' | c -> c
|
|
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 pos_is_valid grid (x, y) =
|
|
x >= 0 && x < grid.width && y >= 0 && y < grid.height
|
|
|
|
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 get_by_pos_opt grid pos =
|
|
if pos_is_valid grid pos then Some (get_by_pos grid pos) else None
|
|
|
|
let idx_from_opt grid = String.index_from_opt grid.grid
|
|
|
|
let update_idx grid idx c =
|
|
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 }
|
|
|
|
let update_pos grid pos c = update_idx grid (idx_of_pos grid pos) c
|
|
end
|
|
|
|
let log10i i =
|
|
let rec impl acc = function 0 -> acc | x -> impl (acc + 1) (x / 10) in
|
|
assert (i > 0);
|
|
impl ~-1 i
|
|
|
|
let digits10 = function
|
|
| 0 -> 1
|
|
| n when n > 0 -> 1 + log10i n
|
|
| n (* when n < 0 *) -> 1 + log10i (-n)
|
|
|
|
let pow10 n =
|
|
let rec impl acc = function 0 -> acc | x -> impl (acc * 10) (x - 1) in
|
|
assert (n >= 0);
|
|
impl 1 n
|
|
|
|
let memoize memo f value =
|
|
match Hashtbl.find_opt memo value with
|
|
| Some x -> x
|
|
| None ->
|
|
let x = f value in
|
|
Hashtbl.add memo value x;
|
|
x
|
|
|
|
let rec apply_n n fn arg = if n <= 0 then arg else apply_n (n - 1) fn (fn arg)
|