96 lines
2.2 KiB
OCaml
96 lines
2.2 KiB
OCaml
open Containers
|
|
|
|
type 'a t =
|
|
{ width : int
|
|
; height : int
|
|
; items : 'a array
|
|
}
|
|
[@@deriving show]
|
|
|
|
let vec2_of_idx ~width ~idx =
|
|
let y = idx / width in
|
|
let x = idx mod width in
|
|
Vec2.of_tuple (x, y)
|
|
;;
|
|
|
|
let idx_of_vec2 width vec = Vec2.(Int.((width * vec.y) + vec.x))
|
|
|
|
let in_bounds grid point =
|
|
let x, y = Vec2.to_tuple point in
|
|
x >= 0 && x < grid.width && y >= 0 && y < grid.height
|
|
;;
|
|
|
|
let at grid point =
|
|
if in_bounds grid point
|
|
then Array.get_safe grid.items @@ idx_of_vec2 grid.width point
|
|
else None
|
|
;;
|
|
|
|
let at_e (grid : 'a t) (point : Vec2.t) =
|
|
Option.get_exn_or "point out of bounds!" @@ at grid point
|
|
;;
|
|
|
|
let set_e grid point item =
|
|
if in_bounds grid point
|
|
then Array.set grid.items (idx_of_vec2 grid.width point) item
|
|
else failwith "point out of bounds!"
|
|
;;
|
|
|
|
let ( .%() ) = at
|
|
let ( .%()<- ) = set_e
|
|
|
|
let find (grid : 'a t) pred =
|
|
let open Option.Infix in
|
|
let* idx, item = Array.find_idx pred grid.items in
|
|
Some (vec2_of_idx ~width:grid.width ~idx, item)
|
|
;;
|
|
|
|
let init ~width ~height init =
|
|
{ width
|
|
; height
|
|
; items = Array.init (width * height) (fun idx -> init @@ vec2_of_idx ~width ~idx)
|
|
}
|
|
;;
|
|
|
|
let of_lines parse_char lines : 'a t =
|
|
match lines with
|
|
| first_line :: _ ->
|
|
let width = String.length first_line in
|
|
let height = List.length lines in
|
|
let yeet =
|
|
lines
|
|
|> List.map String.to_list
|
|
|> List.flatten
|
|
|> List.map parse_char
|
|
|> Array.of_list
|
|
in
|
|
{ width; height; items = yeet }
|
|
| _ -> failwith "somethin fucd up"
|
|
;;
|
|
|
|
let iter_region grid a b callback =
|
|
let open Vec2 in
|
|
for y = min a.y b.y to max a.y b.y do
|
|
for x = min a.x b.x to max a.x b.x do
|
|
let pos = { x; y } in
|
|
if in_bounds grid pos then callback pos
|
|
done
|
|
done
|
|
;;
|
|
|
|
let iter grid callback =
|
|
let a = Vec2.of_tuple (0, 0) in
|
|
let b = Vec2.of_tuple (grid.width - 1, grid.height - 1) in
|
|
iter_region grid a b callback
|
|
;;
|
|
|
|
let draw grid printer =
|
|
let str = ref [] in
|
|
iter grid (fun point ->
|
|
let item = grid.%(point) in
|
|
let char = printer @@ Option.get_exn_or "iter is broken" item in
|
|
str := !str @ [ char ];
|
|
if point.x = grid.width - 1 then str := !str @ [ '\n' ]);
|
|
String.of_list !str
|
|
;;
|