From 4c3a50166bf0f78ce89459c352cc1c6536a8b96d Mon Sep 17 00:00:00 2001 From: DJ O'Leary Date: Sat, 29 Nov 2025 20:23:02 +0100 Subject: chore: make language folders snake_case --- 2024/ocaml/lib/day_01/part_01.ml | 40 ++++++++++++++++++ 2024/ocaml/lib/day_01/part_02.ml | 44 ++++++++++++++++++++ 2024/ocaml/lib/day_02/part_01.ml | 42 +++++++++++++++++++ 2024/ocaml/lib/day_03/part_01.ml | 33 +++++++++++++++ 2024/ocaml/lib/day_04/part_01.ml | 85 +++++++++++++++++++++++++++++++++++++++ 2024/ocaml/lib/day_05/part_01.ml | 62 ++++++++++++++++++++++++++++ 2024/ocaml/lib/dune | 5 +++ 2024/ocaml/lib/file/read_input.ml | 11 +++++ 2024/ocaml/lib/grid/cell.ml | 18 +++++++++ 2024/ocaml/lib/grid/cell.mli | 18 +++++++++ 2024/ocaml/lib/grid/grid.ml | 14 +++++++ 2024/ocaml/lib/grid/grid.mli | 6 +++ 12 files changed, 378 insertions(+) create mode 100644 2024/ocaml/lib/day_01/part_01.ml create mode 100644 2024/ocaml/lib/day_01/part_02.ml create mode 100644 2024/ocaml/lib/day_02/part_01.ml create mode 100644 2024/ocaml/lib/day_03/part_01.ml create mode 100644 2024/ocaml/lib/day_04/part_01.ml create mode 100644 2024/ocaml/lib/day_05/part_01.ml create mode 100644 2024/ocaml/lib/dune create mode 100644 2024/ocaml/lib/file/read_input.ml create mode 100644 2024/ocaml/lib/grid/cell.ml create mode 100644 2024/ocaml/lib/grid/cell.mli create mode 100644 2024/ocaml/lib/grid/grid.ml create mode 100644 2024/ocaml/lib/grid/grid.mli (limited to '2024/ocaml/lib') diff --git a/2024/ocaml/lib/day_01/part_01.ml b/2024/ocaml/lib/day_01/part_01.ml new file mode 100644 index 0000000..100b12a --- /dev/null +++ b/2024/ocaml/lib/day_01/part_01.ml @@ -0,0 +1,40 @@ +(* Day 1: Part 1 *) + +let calculate_distance x y = Stdlib.abs (x - y) + +(** Require: left and right to be the same length *) +let solve left right = + let sorted_left = List.sort Stdlib.compare left in + let sorted_right = List.sort Stdlib.compare right in + let distances = List.map2 calculate_distance sorted_left sorted_right in + List.fold_left ( + ) 0 distances + +let left line = + let pos = 0 in + let len = String.index line ' ' in + String.sub line pos len + +let right line = + let pos = String.rindex line ' ' + 1 in + let len = String.length line - pos in + String.sub line pos len + +let line_to_tuple line = (left line, right line) + +let lines_to_lists lines = + let tuples = List.map line_to_tuple lines in + let left = + List.map + (fun t -> + let l, _ = t in + int_of_string l) + tuples + in + let right = + List.map + (fun t -> + let _, r = t in + int_of_string r) + tuples + in + (left, right) diff --git a/2024/ocaml/lib/day_01/part_02.ml b/2024/ocaml/lib/day_01/part_02.ml new file mode 100644 index 0000000..25c8b7d --- /dev/null +++ b/2024/ocaml/lib/day_01/part_02.ml @@ -0,0 +1,44 @@ +(* Day 1: Part 2 *) + +let rec count_occurrances_help element acc lst = + match lst with + | [] -> acc + | h :: t -> + if h = element then count_occurrances_help element (acc + 1) t + else count_occurrances_help element acc t + +let count_occurrances element lst = count_occurrances_help element 0 lst + +let solve left right = + List.map (fun x -> x * count_occurrances x right) left + |> List.fold_left ( + ) 0 + +let left line = + let pos = 0 in + let len = String.index line ' ' in + String.sub line pos len + +let right line = + let pos = String.rindex line ' ' + 1 in + let len = String.length line - pos in + String.sub line pos len + +let line_to_tuple line = (left line, right line) + +let lines_to_lists lines = + let tuples = List.map line_to_tuple lines in + let left = + List.map + (fun t -> + let l, _ = t in + int_of_string l) + tuples + in + let right = + List.map + (fun t -> + let _, r = t in + int_of_string r) + tuples + in + (left, right) diff --git a/2024/ocaml/lib/day_02/part_01.ml b/2024/ocaml/lib/day_02/part_01.ml new file mode 100644 index 0000000..32d7ab8 --- /dev/null +++ b/2024/ocaml/lib/day_02/part_01.ml @@ -0,0 +1,42 @@ +(* Day 2: Part 1 *) + +type level = int +type reports = level list list + +let rec compare_report_levels_helper comparison prev report = + match report with + | [] -> true + | h :: t -> comparison prev h && compare_report_levels_helper comparison h t + +let compare_report_levels comparison report = + match report with + | [] -> true + | h :: t -> compare_report_levels_helper comparison h t + +let all_increasing report = compare_report_levels ( < ) report +let all_decreasing report = compare_report_levels ( > ) report + +let at_least_one report = + compare_report_levels (fun prev curr -> prev <> curr) report + +let at_most_three report = + compare_report_levels (fun prev curr -> abs (prev - curr) <= 3) report + +let check_report_safety report = + if not (all_increasing report || all_decreasing report) then false + else if not (at_least_one report && at_most_three report) then false + else true + +let rec count_safe_reports acc lst = + match lst with + | [] -> acc + | h :: t -> + if h then count_safe_reports (acc + 1) t else count_safe_reports acc t + +let solve reports = + reports |> List.map check_report_safety |> count_safe_reports 0 + +let line_to_report line = + line |> String.split_on_char ' ' |> List.map int_of_string + +let lines_to_reports lines = List.map line_to_report lines diff --git a/2024/ocaml/lib/day_03/part_01.ml b/2024/ocaml/lib/day_03/part_01.ml new file mode 100644 index 0000000..c12b68a --- /dev/null +++ b/2024/ocaml/lib/day_03/part_01.ml @@ -0,0 +1,33 @@ +(* Day 3: Part 1 *) + +let find_mul text = + let regex_or_err = Re2.create "mul\\(([0-9]{1,3}),([0-9]{1,3})\\)" in + match regex_or_err with + | Ok regex -> ( + let matches = Re2.get_matches regex text in + match matches with Ok matches -> matches | Error _ -> []) + | Error _ -> [] + +let extract_pairs (matches : Re2.Match.t list) : (int * int) list = + List.map + (fun x -> + let left = Re2.Match.get x ~sub:(`Index 1) in + match left with + | None -> (0, 0) + | Some left -> ( + let left_num = int_of_string left in + let right = Re2.Match.get x ~sub:(`Index 2) in + match right with + | None -> (0, 0) + | Some right -> + let right_num = int_of_string right in + (left_num, right_num))) + matches + +let solve input = + input |> find_mul |> extract_pairs + |> List.fold_left + (fun acc pair -> + let left, right = pair in + acc + (left * right)) + 0 diff --git a/2024/ocaml/lib/day_04/part_01.ml b/2024/ocaml/lib/day_04/part_01.ml new file mode 100644 index 0000000..acb3e3b --- /dev/null +++ b/2024/ocaml/lib/day_04/part_01.ml @@ -0,0 +1,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 diff --git a/2024/ocaml/lib/day_05/part_01.ml b/2024/ocaml/lib/day_05/part_01.ml new file mode 100644 index 0000000..f32bef1 --- /dev/null +++ b/2024/ocaml/lib/day_05/part_01.ml @@ -0,0 +1,62 @@ +(* Day 5: Part 1 *) + +module StringMap = Map.Make (String) + +let inverse_page_rule page_rule = + String.split_on_char '|' page_rule |> fun lst -> + match lst with [] -> "" | _ :: _ -> String.concat "|" (List.rev lst) + +(** [parse_aux acc page_rules] is a map of all invalid transitions as defined by + [page_rules] *) +let rec get_invalid_transitions_aux acc page_rules : unit StringMap.t = + match page_rules with + | [] -> acc + | h :: t -> + get_invalid_transitions_aux + (acc |> StringMap.add (inverse_page_rule h) ()) + t + +let get_invalid_transitions page_rules = + get_invalid_transitions_aux StringMap.empty page_rules + +(** [solve page_rules updates] is the solution for this puzzle, given the + [page_rules] and a list of [updates]. + + BELOW DOESN'T WORK: no guarantee that second page comes immediately after + the first + - pass in updates to solve + - make sliding window of 2 elements + - invert element order and concat + - check if key is in map from [parse page_rules], + - if yes, then it is an illegal transition + - if no, then add the list to a list for further processing *) +let solve page_rules _ = + let invalid_transitions = get_invalid_transitions page_rules in + () + +let _ = + solve + [ + "47|53"; + "97|13"; + "97|61"; + "97|47"; + "75|29"; + "61|13"; + "75|53"; + "29|13"; + "97|29"; + "53|29"; + "61|53"; + "97|53"; + "61|29"; + "47|13"; + "75|47"; + "97|75"; + "47|61"; + "75|61"; + "47|29"; + "75|13"; + "53|13"; + ] + [] diff --git a/2024/ocaml/lib/dune b/2024/ocaml/lib/dune new file mode 100644 index 0000000..84e62ca --- /dev/null +++ b/2024/ocaml/lib/dune @@ -0,0 +1,5 @@ +(library + (name AoC_2024) + (libraries re2)) + +(include_subdirs qualified) diff --git a/2024/ocaml/lib/file/read_input.ml b/2024/ocaml/lib/file/read_input.ml new file mode 100644 index 0000000..0f7470b --- /dev/null +++ b/2024/ocaml/lib/file/read_input.ml @@ -0,0 +1,11 @@ +let rec lines_from_channel ic = + try + let line = input_line ic in + line :: lines_from_channel ic + with End_of_file -> [] + +let lines_from_file filename = + let channel = open_in filename in + let lines = lines_from_channel channel in + close_in channel; + lines diff --git a/2024/ocaml/lib/grid/cell.ml b/2024/ocaml/lib/grid/cell.ml new file mode 100644 index 0000000..186e451 --- /dev/null +++ b/2024/ocaml/lib/grid/cell.ml @@ -0,0 +1,18 @@ +type t = { + value : string; + up : t option; + down : t option; + left : t option; + right : t option; +} + +let create value = { value; up = None; down = None; left = None; right = None } +let with_up up c = { c with up = Some up } +let with_down down c = { c with down = Some down } +let with_left left c = { c with left = Some left } +let with_right right c = { c with right = Some right } +let move_up co = match co with Some c -> c.up | None -> None +let move_down co = match co with Some c -> c.down | None -> None +let move_left co = match co with Some c -> c.left | None -> None +let move_right co = match co with Some c -> c.right | None -> None +let ( = ) c1 c2 = c1.value = c2.value diff --git a/2024/ocaml/lib/grid/cell.mli b/2024/ocaml/lib/grid/cell.mli new file mode 100644 index 0000000..e61e34a --- /dev/null +++ b/2024/ocaml/lib/grid/cell.mli @@ -0,0 +1,18 @@ +type t = { + value : string; + up : t option; + down : t option; + left : t option; + right : t option; +} + +val create : string -> t +val with_up : t -> t -> t +val with_down : t -> t -> t +val with_left : t -> t -> t +val with_right : t -> t -> t +val move_up : t option -> t option +val move_down : t option -> t option +val move_left : t option -> t option +val move_right : t option -> t option +val ( = ) : t -> t -> bool diff --git a/2024/ocaml/lib/grid/grid.ml b/2024/ocaml/lib/grid/grid.ml new file mode 100644 index 0000000..0d6bc4c --- /dev/null +++ b/2024/ocaml/lib/grid/grid.ml @@ -0,0 +1,14 @@ +let rec to_grid_aux tokens max_width acc = + match tokens with + | [] -> acc + | h :: t -> + let new_cell = Cell.create h |> Cell.with_left acc in + let new_acc = acc |> Cell.with_right new_cell in + to_grid_aux t max_width new_acc + +let to_grid tokens max_width : Cell.t option = + match tokens with + | [] -> None + | h :: t -> + let first_cell = Cell.create h in + Some (to_grid_aux t max_width first_cell) diff --git a/2024/ocaml/lib/grid/grid.mli b/2024/ocaml/lib/grid/grid.mli new file mode 100644 index 0000000..a69fcfe --- /dev/null +++ b/2024/ocaml/lib/grid/grid.mli @@ -0,0 +1,6 @@ +val to_grid : string list -> int -> Cell.t option +(** The cell in the top left corner of the grid is returned where each element + of [tokens] is converted into rows with [width]. An empty list of [tokens] + returns None. Requires: [width] is greater than 0 **) + +(* val print : Cell.t -> () *) -- cgit v1.2.3