114 lines
3.5 KiB
OCaml
114 lines
3.5 KiB
OCaml
open Printf;;
|
|
open Buffer;;
|
|
open Str;;
|
|
|
|
let rec list_of_lines in_file =
|
|
try
|
|
let line = input_line in_file in
|
|
line :: list_of_lines(in_file)
|
|
with End_of_file ->
|
|
close_in in_file;
|
|
[]
|
|
|
|
let file_to_2d_array in_file =
|
|
let lines = list_of_lines in_file in
|
|
let size_x = String.length @@ List.hd lines in
|
|
let size_y = List.length lines in
|
|
let arr = Array.make_matrix size_x size_y '?' in
|
|
List.iteri (fun j line -> String.iteri (fun i c -> arr.(j).(i) <- c) line) lines;
|
|
arr
|
|
|
|
let rec count_in_string_inner re str pos acc =
|
|
try
|
|
let new_pos = Str.search_forward re str pos in
|
|
count_in_string_inner re str (new_pos + 1) (acc + 1)
|
|
with Not_found -> acc
|
|
|
|
let count_in_string str =
|
|
let re = Str.regexp "XMAS\\|SAMX" in
|
|
count_in_string_inner re str 0 0
|
|
|
|
let prepare_horizontal_str arr =
|
|
let buf = Buffer.create 1024 in
|
|
Array.iter (fun row -> Array.iter (fun c -> Buffer.add_char buf c) row; Buffer.add_char buf '\n') arr;
|
|
Buffer.contents buf
|
|
|
|
let prepare_vertical_str arr =
|
|
let buf = Buffer.create 1024 in
|
|
Seq.iter (fun i -> Array.iter (fun row -> Buffer.add_char buf row.(i)) arr; Buffer.add_char buf '\n')
|
|
(Seq.init (Array.length arr.(0)) (fun x -> x));
|
|
Buffer.contents buf
|
|
|
|
let rec traverse_diagonal fn arr x y =
|
|
try
|
|
let () = fn arr.(y).(x) in
|
|
traverse_diagonal fn arr (x + 1) (y + 1)
|
|
with Invalid_argument _ -> ()
|
|
|
|
let rec traverse_antidiagonal fn arr x y =
|
|
try
|
|
let () = fn arr.(y).(x) in
|
|
traverse_antidiagonal fn arr (x - 1) (y + 1)
|
|
with Invalid_argument _ -> ()
|
|
|
|
let range start stop =
|
|
Seq.init (stop - start) (fun x -> start + x)
|
|
|
|
let range_rev start stop =
|
|
Seq.init (stop - start) (fun x -> stop - 1 - x)
|
|
|
|
let prepare_diagonal_str arr =
|
|
let buf = Buffer.create 1024 in
|
|
let length_x = Array.length arr.(0) in
|
|
let length_y = Array.length arr in
|
|
Seq.iter (fun y -> traverse_diagonal (Buffer.add_char buf) arr 0 y; Buffer.add_char buf '\n')
|
|
(range_rev 1 (length_y - 1));
|
|
Seq.iter (fun x -> traverse_diagonal (Buffer.add_char buf) arr x 0; Buffer.add_char buf '\n')
|
|
(range 0 length_x);
|
|
Buffer.contents buf
|
|
|
|
let prepare_antidiagonal_str arr =
|
|
let buf = Buffer.create 1024 in
|
|
let length_x = Array.length arr.(0) in
|
|
let length_y = Array.length arr in
|
|
Seq.iter (fun x -> traverse_antidiagonal (Buffer.add_char buf) arr x 0; Buffer.add_char buf '\n')
|
|
(range 0 length_x);
|
|
Seq.iter (fun y -> traverse_antidiagonal (Buffer.add_char buf) arr (length_x - 1) y; Buffer.add_char buf '\n')
|
|
(range 1 (length_y - 1));
|
|
Buffer.contents buf
|
|
|
|
let is_mas_x arr x y =
|
|
if arr.(y).(x) = 'A' then
|
|
let nw = arr.(y - 1).(x - 1) in
|
|
let se = arr.(y + 1).(x + 1) in
|
|
if (nw = 'M' && se = 'S') || (nw = 'S' && se = 'M') then
|
|
let ne = arr.(y - 1).(x + 1) in
|
|
let sw = arr.(y + 1).(x - 1) in
|
|
(ne = 'M' && sw = 'S') || (ne = 'S' && sw = 'M')
|
|
else
|
|
false
|
|
else
|
|
false
|
|
|
|
let count_mas_x arr =
|
|
let length_x = Array.length arr.(0) in
|
|
let length_y = Array.length arr in
|
|
Seq.fold_left
|
|
(fun acc y -> acc +
|
|
Seq.fold_left
|
|
(fun acc x -> acc +
|
|
if is_mas_x arr x y then 1 else 0)
|
|
0 (range 1 (length_x - 1)))
|
|
0 (range 1 (length_y - 1))
|
|
|
|
let () =
|
|
let f = open_in "input.txt" in
|
|
let arr = file_to_2d_array f in
|
|
let counter =
|
|
(count_in_string @@ prepare_horizontal_str arr)
|
|
+ (count_in_string @@ prepare_vertical_str arr)
|
|
+ (count_in_string @@ prepare_diagonal_str arr)
|
|
+ (count_in_string @@ prepare_antidiagonal_str arr) in
|
|
let counter2 = count_mas_x arr in
|
|
printf "%d\n" counter;
|
|
printf "%d\n" counter2 |