blob: acb3e3b8ff57e489e9b6e8886f909d70bd7ccb3b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
(* Day 4: Part 1 *)
type character = { index : int; character : char }
type direction = N | NE | E | SE | S | SW | W | NW
let all_directions = [ N; NE; E; SE; S; SW; W; NW ]
let needle = "XMAS"
(** [calculate_row_offset lines] is the offset used to move between the rows of
the concatenated variant of [lines] as though it were a grid. Requires:
values of [lines] all have the same length *)
let calculate_row_offset lines =
match lines with [] -> 0 | h :: _ -> String.length h
let join_lines lines =
let concat_trim acc line = acc ^ String.trim line in
List.fold_left concat_trim "" lines
let explode s = List.init (String.length s) (String.get s)
let is_in_bounds length index = index >= 0 && index < length
let get_at_index line index =
let length = String.length line in
if not (is_in_bounds length index) then "."
else
let character = String.get line index in
Char.escaped character
let get_direction_index row_offset direction index =
match direction with
| N -> index - row_offset
| NE -> index - row_offset + 1
| E -> index + 1
| SE -> index + row_offset + 1
| S -> index + row_offset
| SW -> index + row_offset - 1
| W -> index - 1
| NW -> index - row_offset - 1
let get_direction_string get_char get_offset_index index =
let first = get_char index in
let second_index = get_offset_index index in
let second = get_char second_index in
let third_index = get_offset_index second_index in
let third = get_char third_index in
let fourth_index = get_offset_index third_index in
let fourth = get_char fourth_index in
first ^ second ^ third ^ fourth
let check_direction get_from_line get_offset_index index direction =
get_direction_string get_from_line (get_offset_index direction) index = needle
let calculate_num_of_matches line row_offset character =
let get_from_line_at_index = get_at_index line in
let get_offset_direction_index = get_direction_index row_offset in
let check_direction_from_index =
check_direction get_from_line_at_index get_offset_direction_index
character.index
in
all_directions
|> List.map check_direction_from_index
|> List.map (fun x -> match x with true -> 1 | false -> 0)
|> List.fold_left ( + ) 0
(* Tried:
2544 -> too high
1272 (previous halved) -> too low *)
let solve lines =
let row_offset = calculate_row_offset lines in
let line = join_lines lines in
let chars = explode line in
let characters = List.mapi (fun i c -> { index = i; character = c }) chars in
let xs =
List.filter
(fun c -> match c.character with 'X' -> true | _ -> false)
characters
in
let calculate_num_of_surrounding_matches_in_line =
calculate_num_of_matches line row_offset
in
let num_of_matches =
List.map calculate_num_of_surrounding_matches_in_line xs
|> List.fold_left ( + ) 0
in
num_of_matches
|