From e07537d56df357795c21d660847aa1e411241456 Mon Sep 17 00:00:00 2001 From: Caleb Webber Date: Sat, 2 Dec 2023 02:13:16 -0500 Subject: [PATCH] 2023 day1 --- lib/2023_day1.ex | 133 ++++++++++++++++++++++++++++++++++++++++++++++ lib/2023_day1.exs | 103 +++++++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 lib/2023_day1.ex create mode 100644 lib/2023_day1.exs diff --git a/lib/2023_day1.ex b/lib/2023_day1.ex new file mode 100644 index 0000000..f5b34f4 --- /dev/null +++ b/lib/2023_day1.ex @@ -0,0 +1,133 @@ +defmodule Day1_2024 do + def solve(input) do + input + |> Enum.filter(&(String.length(&1) > 0)) + |> Enum.reduce( + 0, + fn line, acc -> + acc + parse_number(line) + end + ) + end + + def parse_number(line) do + left_number = find_first_number(line) + right_number = find_first_number_from_right(line) + left_number * 10 + right_number + end + + def find_first_number(l) do + 1..(l |> String.length()) + |> Enum.reduce_while( + 0, + fn i, _ -> + int_at_pos = l |> String.at(i - 1) |> Integer.parse() + + case int_at_pos do + :error -> + l + |> String.slice(0, i) + |> search_for_written_number() + |> then(fn res -> + case res do + nil -> {:cont, 0} + n -> {:halt, n} + end + end) + + n -> + {:halt, n |> elem(0)} + end + end + ) + end + + def find_first_number_from_right(l) do + len = String.length(l) + + 1..len + |> Enum.reduce_while( + 0, + fn i, _ -> + cur_char = l |> String.at(len - i) + IO.puts("examining ") + IO.puts(cur_char) + int_at_pos = cur_char |> Integer.parse() + + case int_at_pos do + :error -> + l + |> String.slice(len - i, len) + |> search_for_written_number() + |> then(fn res -> + case res do + nil -> {:cont, 0} + n -> {:halt, n} + end + end) + + {n, _} -> + {:halt, n} + end + end + ) + end + + def search_for_written_number(line) do + IO.puts("searching " <> line) + + numbers = [ + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine" + ] + + numbers_map = %{ + "one" => 1, + "two" => 2, + "three" => 3, + "four" => 4, + "five" => 5, + "six" => 6, + "seven" => 7, + "eight" => 8, + "nine" => 9 + } + + if String.length(line) < 3 do + nil + else + splits = + numbers + |> Enum.map(fn number -> + split = String.split(line, number) + {number, split |> Enum.map(&(&1 |> String.length()))} + end) + |> Enum.filter(&(&1 |> elem(1) |> Enum.count() > 1)) + + IO.puts(inspect(splits)) + + number_word = + splits + |> Enum.sort_by(fn split -> + split |> elem(1) |> List.first() + end) + |> Enum.at(0) + + res = + if is_tuple(number_word) do + Map.get(numbers_map, number_word |> elem(0)) + else + nil + end + + res + end + end +end diff --git a/lib/2023_day1.exs b/lib/2023_day1.exs new file mode 100644 index 0000000..94ed5b8 --- /dev/null +++ b/lib/2023_day1.exs @@ -0,0 +1,103 @@ +defmodule Day1 do + @numbers [ + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine" + ] + + def read_calibration_values(s) do + IO.puts(s) + [scan_left_for_number(s), scan_right_for_number(s)] + end + + def if_nil_cont(u) do + case u do + nil -> {:cont, nil} + o -> {:halt, o} + end + end + + def index_of(haystack, needle) do + len = String.length(haystack) + + haystack + |> String.split(needle) + |> Enum.at(0) + |> then(fn x -> + case x do + len -> :error + n -> n + end + end) + end + + def search_number_word(s) do + @numbers + |> Enum.with_index() + |> Stream.transform( + [], + fn {number, index}, acc -> + case index_of(s, number) do + :error -> acc + n -> [{index + 1, n} | acc] + end + end + ) + |> Enum.sort_by(&(&1 |> elem(1))) + |> Enum.at(0) + end + + def find_number(s) do + s + |> String.last() + |> Integer.parse() + |> then(fn u -> + case u do + :error -> search_number_word(s) + {i, _} -> i + end + end) + end + + def scan_left_for_number(s) do + len = String.length(s) + + 0..len + |> Enum.reduce_while( + 0, + &(find_number(s |> String.slice(0..&1)) |> if_nil_cont()) + ) + |> Enum.reduce( + 0, + &(&1 + &2) + ) + end + + defp scan_right_for_number(s) do + len = String.length(s) + + 0..(len - 1) + |> Enum.reduce_while( + 0, + &(find_number(s |> String.slice((-1 - &1)..-1)) |> if_nil_cont()) + ) + |> Enum.reduce( + 0, + &(&1 + &2) + ) + end +end + +for line <- IO.stream(), reduce: 0 do + acc -> + line |> IO.puts() + [first, last] = line |> Day1.read_calibration_values() + acc + (first * 10 + last) +end +|> IO.puts()