94 lines
2.7 KiB
OCaml
94 lines
2.7 KiB
OCaml
let check_at grid x y =
|
|
if x < 0 || x >= Array.length grid.(0) || y < 0 || y >= Array.length grid then
|
|
None
|
|
else Some grid.(y).(x)
|
|
|
|
let get_next_char c =
|
|
match c with
|
|
| 'M' -> 'A'
|
|
| 'A' -> 'S'
|
|
| _ -> raise (Invalid_argument "cant put this here")
|
|
|
|
let rec check_work_in_direction grid x y starting_char direction path =
|
|
let dx, dy = direction in
|
|
let grid_char = check_at grid (x + dx) (y + dy) in
|
|
match grid_char with
|
|
| None -> 0
|
|
| Some c ->
|
|
if c != starting_char then 0
|
|
else if c == 'S' then 1
|
|
else
|
|
check_work_in_direction grid (x + dx) (y + dy)
|
|
(get_next_char starting_char)
|
|
direction
|
|
([ (x + dx, y + dy) ] @ path)
|
|
|
|
let is_char op cc = match op with None -> false | Some c -> c == cc
|
|
|
|
let check_word_part2 grid x y =
|
|
let grid_char = check_at grid x y in
|
|
match grid_char with
|
|
| None -> false
|
|
| Some 'A' ->
|
|
let top_left = check_at grid (x - 1) (y - 1) in
|
|
let top_right = check_at grid (x + 1) (y - 1) in
|
|
let bottom_left = check_at grid (x - 1) (y + 1) in
|
|
let bottom_right = check_at grid (x + 1) (y + 1) in
|
|
|
|
let is_back_diagal_mas =
|
|
(is_char top_left 'S' && is_char bottom_right 'M')
|
|
|| (is_char top_left 'M' && is_char bottom_right 'S')
|
|
in
|
|
|
|
let is_forward_diagal_mas =
|
|
(is_char top_right 'S' && is_char bottom_left 'M')
|
|
|| (is_char top_right 'M' && is_char bottom_left 'S')
|
|
in
|
|
|
|
is_back_diagal_mas && is_forward_diagal_mas
|
|
| Some _ -> false
|
|
|
|
let check_word grid x y =
|
|
let grid_char = check_at grid x y in
|
|
let curried_check = check_work_in_direction grid x y 'M' in
|
|
match grid_char with
|
|
| None -> 0
|
|
| Some 'X' ->
|
|
curried_check (-1, -1) [ (x, y) ]
|
|
+ curried_check (0, -1) [ (x, y) ]
|
|
+ curried_check (1, -1) [ (x, y) ]
|
|
+ curried_check (-1, 0) [ (x, y) ]
|
|
+ curried_check (1, 0) [ (x, y) ]
|
|
+ curried_check (-1, 1) [ (x, y) ]
|
|
+ curried_check (0, 1) [ (x, y) ]
|
|
+ curried_check (1, 1) [ (x, y) ]
|
|
| Some _ -> 0
|
|
|
|
let solve lines =
|
|
let grid =
|
|
Array.init (List.length lines) (fun i ->
|
|
Array.init
|
|
(String.length (List.nth lines 0))
|
|
(fun j -> String.get (List.nth lines i) j))
|
|
in
|
|
|
|
let x_list = List.init (Array.length grid.(0)) (fun i -> i) in
|
|
let y_list = List.init (Array.length grid) (fun i -> i) in
|
|
|
|
let part1 =
|
|
List.fold_left
|
|
(fun acc y ->
|
|
acc + List.fold_left (fun acc x -> acc + check_word grid x y) 0 x_list)
|
|
0 y_list
|
|
in
|
|
let part2 =
|
|
List.fold_left
|
|
(fun acc y ->
|
|
acc
|
|
+ List.fold_left
|
|
(fun acc x -> acc + if check_word_part2 grid x y then 1 else 0)
|
|
0 x_list)
|
|
0 y_list
|
|
in
|
|
(part1, part2)
|