115 lines
2.4 KiB
Elixir
115 lines
2.4 KiB
Elixir
|
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
|