Day 9 Parts 1 and 2
This commit is contained in:
parent
3784d613f6
commit
8e7f5288ce
5 changed files with 1165 additions and 1 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
My (attempted) solutions to [Advent of Code 2020](https://adventofcode.com/2020) in Elixir.
|
||||
|
||||
<img width="975" alt="image" src="https://user-images.githubusercontent.com/498229/101474250-39a22900-398e-11eb-9716-42b0d65171e4.png">
|
||||
<img width="975" alt="image" src="https://user-images.githubusercontent.com/498229/101621087-a71a8c00-3a58-11eb-9cf5-ca816dbba6ee.png">
|
||||
|
||||
## Strategy
|
||||
|
||||
|
|
52
day9/README
Normal file
52
day9/README
Normal file
|
@ -0,0 +1,52 @@
|
|||
Day 9 Notes
|
||||
|
||||
+--------+
|
||||
| Part 1 |
|
||||
+--------+
|
||||
|
||||
$ elixir day9part1.exs
|
||||
18272118
|
||||
|
||||
Thoughts:
|
||||
|
||||
Searching inside a sliding window.
|
||||
|
||||
Tricky to write efficiently in an immutable language.
|
||||
I knew what I wanted to do, but working out how to write that took a lot of thought.
|
||||
The solution completes in just over 1ms, so I'm pretty happy with it.
|
||||
|
||||
Every time the window slides, I decided to sort it, which means I could take the following shortcuts:
|
||||
* When selecting the first number in the pair, stop early if added to the first number in the preamble it's
|
||||
greater than the target, because we know the rest of the numbers are also too large.
|
||||
* Similarly can do the same when checking for the second number in the pair.
|
||||
* Avoids comparing pairs we already compared.
|
||||
|
||||
|
||||
+--------+
|
||||
| Part 2 |
|
||||
+--------+
|
||||
|
||||
$ elixir day9part2.exs
|
||||
2186361
|
||||
|
||||
Thoughts:
|
||||
|
||||
Initially hard-coded the answer from part 1, but then decided to re-use part one and pass it as an
|
||||
input to keep the solution fully dynamic.
|
||||
|
||||
Similar to part 1, but now we have to check an unknown number of adjacent items. Again stop checking each
|
||||
group as soon as the sum is too big, and move to the next group.
|
||||
|
||||
This answer also completes in about a millisecond (not including part 1).
|
||||
|
||||
P.S. I accidentally copied part 1 over part 2 after solving this, and had to write the solution again 🤦🏼♂️
|
||||
|
||||
+------------------+
|
||||
| Overall Thoughts |
|
||||
+------------------+
|
||||
|
||||
The most challenging thing here was working out how to write it in an immutable, recursive way cleanly.
|
||||
I was considering using the :array module, but I think I managed to get everything working nicely with
|
||||
lists without the need to do lots of expensive list-indexing. Pretty sure both answers are O(nlogn).
|
||||
|
||||
Probably will tidy up this more later, especailly Part 1, but done for now.
|
41
day9/day9part1.exs
Normal file
41
day9/day9part1.exs
Normal file
|
@ -0,0 +1,41 @@
|
|||
defmodule Day9Part1 do
|
||||
def run do
|
||||
File.read!("input")
|
||||
|> String.split("\n", trim: true)
|
||||
|> Enum.map(&String.to_integer/1)
|
||||
|> find_invalid()
|
||||
|> IO.puts()
|
||||
end
|
||||
|
||||
def find_invalid([_ | next] = numbers) do
|
||||
{preamble, [number | _]} = Enum.split(numbers, 25)
|
||||
sorted_preamble = Enum.sort(preamble)
|
||||
max = number - hd(sorted_preamble)
|
||||
|
||||
if sum_in_preamble?(sorted_preamble, max, number) do
|
||||
find_invalid(next)
|
||||
else
|
||||
number
|
||||
end
|
||||
end
|
||||
|
||||
def sum_in_preamble?([], _max, _number), do: false
|
||||
|
||||
def sum_in_preamble?([preamble_head | _], max, _number) when preamble_head >= max, do: false
|
||||
|
||||
def sum_in_preamble?([preamble_head | preamble_rest], max, number) do
|
||||
if forms_pair?(preamble_head, preamble_rest, max, number) do
|
||||
true
|
||||
else
|
||||
sum_in_preamble?(preamble_rest, max, number)
|
||||
end
|
||||
end
|
||||
|
||||
def forms_pair?(_, [y | _], max, _number) when y > max, do: false
|
||||
|
||||
def forms_pair?(x, preamble_rest, _max, number) do
|
||||
Enum.any?(preamble_rest, fn y -> x + y == number end)
|
||||
end
|
||||
end
|
||||
|
||||
Day9Part1.run()
|
71
day9/day9part2.exs
Normal file
71
day9/day9part2.exs
Normal file
|
@ -0,0 +1,71 @@
|
|||
defmodule Day9Part2 do
|
||||
def run do
|
||||
input =
|
||||
File.read!("input")
|
||||
|> String.split("\n", trim: true)
|
||||
|> Enum.map(&String.to_integer/1)
|
||||
|
||||
invalid_number = Day9Part1.find_invalid(input)
|
||||
|
||||
input
|
||||
|> find_weakness(invalid_number)
|
||||
|> IO.puts()
|
||||
end
|
||||
|
||||
def find_weakness([current | rest], invalid_number) do
|
||||
case find_group(rest, [current], current, invalid_number) do
|
||||
{:ok, group} -> Enum.min(group) + Enum.max(group)
|
||||
_ -> find_weakness(rest, invalid_number)
|
||||
end
|
||||
end
|
||||
|
||||
def find_group(_list, group, sum, target) when sum == target, do: {:ok, group}
|
||||
def find_group(_list, _group, sum, target) when sum > target, do: :too_big
|
||||
def find_group(_list, [], _sum, _target), do: :eol
|
||||
|
||||
def find_group([next | rest], group, sum, target) do
|
||||
find_group(rest, [next | group], sum + next, target)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Day9Part1 do
|
||||
def run do
|
||||
File.read!("input")
|
||||
|> String.split("\n", trim: true)
|
||||
|> Enum.map(&String.to_integer/1)
|
||||
|> find_invalid()
|
||||
|> IO.puts()
|
||||
end
|
||||
|
||||
def find_invalid([_ | next] = numbers) do
|
||||
{preamble, [number | _]} = Enum.split(numbers, 25)
|
||||
sorted_preamble = Enum.sort(preamble)
|
||||
max = number - hd(sorted_preamble)
|
||||
|
||||
if sum_in_preamble?(sorted_preamble, max, number) do
|
||||
find_invalid(next)
|
||||
else
|
||||
number
|
||||
end
|
||||
end
|
||||
|
||||
def sum_in_preamble?([], _max, _number), do: false
|
||||
|
||||
def sum_in_preamble?([preamble_head | _], max, _number) when preamble_head >= max, do: false
|
||||
|
||||
def sum_in_preamble?([preamble_head | preamble_rest], max, number) do
|
||||
if forms_pair?(preamble_head, preamble_rest, max, number) do
|
||||
true
|
||||
else
|
||||
sum_in_preamble?(preamble_rest, max, number)
|
||||
end
|
||||
end
|
||||
|
||||
def forms_pair?(_, [y | _], max, _number) when y > max, do: false
|
||||
|
||||
def forms_pair?(x, preamble_rest, _max, number) do
|
||||
Enum.any?(preamble_rest, fn y -> x + y == number end)
|
||||
end
|
||||
end
|
||||
|
||||
Day9Part2.run()
|
1000
day9/input
Normal file
1000
day9/input
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue