defmodule Day9 do @example """ 35 20 15 25 47 40 62 55 65 95 102 117 150 182 127 219 299 277 309 576 """ @example_premable_length 5 def part1(example \\ false) do input = if example, do: @example, else: File.read!("lib/day9/input.txt") length = if example, do: @example_premable_length, else: 25 input |> parse_input() |> find_first_non_sum(length) end def part2(example \\ false) do input = if example, do: @example, else: File.read!("lib/day9/input.txt") length = if example, do: @example_premable_length, else: 25 input = parse_input(input) non_sum = find_first_non_sum(input, length) {start, length} = find_range_that_sums_to(input, non_sum) {_, after_start} = Enum.split(input, start) {range, _} = Enum.split(after_start, length) Enum.min(range) + Enum.max(range) end def parse_input(input) do input |> String.trim() |> String.split("\n") |> Enum.map(&String.to_integer/1) end def find_first_non_sum([_ | rest] = input, length) do if is_number_sum_of_pairs_first(input, length) do find_first_non_sum(rest, length) else {_, [non_sum | _]} = Enum.split(input, length) non_sum end end def is_number_sum_of_pairs_first(inputs, count) do {before, [first | _]} = Enum.split(inputs, count) before |> all_pairs() |> Enum.any?(fn {a, b} -> # IO.puts("check if #{a} + #{b} == #{first}") a + b == first end) end def all_pairs(inputs) do inputs |> Enum.drop(-1) |> Enum.with_index() |> Enum.flat_map(fn {a, a_index} -> {_, rest} = Enum.split(inputs, a_index + 1) Enum.map(rest, fn b -> {a, b} end) end) end def find_range_that_sums_to([_ | rest] = numbers, target, start \\ 0) do case do_find_leading_range_that_sums_to(numbers, target) do false -> find_range_that_sums_to(rest, target, start + 1) count when is_integer(count) -> {start, count} end end def do_find_leading_range_that_sums_to(numbers, remaining, count \\ 0) def do_find_leading_range_that_sums_to(_, 0, count) do count end def do_find_leading_range_that_sums_to([head | rest], remaining, count) do # IO.puts("trying start: #{start} count: #{count}, target: #{target}") if head <= remaining do do_find_leading_range_that_sums_to(rest, remaining - head, count + 1) else false end end end