···
-
<!-- vim: syntax=markdown -->
-
<!-- livebook:{"persist_outputs":true} -->
···
···
|> Stream.map(&String.to_integer(String.trim(&1)))
-
modes: [:raw, :read_ahead, :binary],
-
funs: [#Function<47.58486609/1 in Stream.map/2>]
···
|> Enum.count(fn [a, b] -> a < b end)
<!-- livebook:{"break_markdown":true} -->
···
|> Enum.count(fn [a, _, _, b] -> a < b end)
···
-
modes: [:raw, :read_ahead, :binary],
-
funs: [#Function<47.58486609/1 in Stream.map/2>]
···
···
···
-
{:module, Day3, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:count, 1}}
···
···
···
+
livebook:{"persist_outputs":true}
···
···
|> Stream.map(&String.to_integer(String.trim(&1)))
···
|> Enum.count(fn [a, b] -> a < b end)
<!-- livebook:{"break_markdown":true} -->
···
|> Enum.count(fn [a, _, _, b] -> a < b end)
···
···
···
···
···
···
+
This time it is a little bit more convoluted, as there are 2 parts of the input.
+
Fortunately we can easily disect the parts via pattern matching.
+
Technically the conversion to the numbers is not needed, but it does no harm
+
and provides additional layer of safety against some whitespace characters left there
+
The `Day4.win/2` function is manually unrolled, as it is easier to write than some
+
random jumping in the list.
+
<!-- livebook:{"disable_formatting":true} -->
+
|> String.split("\n\n", trim: true)
+
|> Enum.map(&String.to_integer/1)
+
|> Enum.map(fn bingo ->
+
|> String.split(~r/\s+/, trim: true)
+
|> Enum.map(&String.to_integer/1)
+
all_in([a1, a2, a3, a4, a5], nums) or
+
all_in([b1, b3, b3, b4, b5], nums) or
+
all_in([c1, c2, c3, c4, c5], nums) or
+
all_in([d1, d2, d3, d4, d5], nums) or
+
all_in([e1, e2, e3, e4, e5], nums) or
+
all_in([a1, b1, c1, d1, e1], nums) or
+
all_in([a2, b2, c2, d2, e2], nums) or
+
all_in([a3, b3, c3, d3, e3], nums) or
+
all_in([a4, b4, c4, d4, e4], nums) or
+
all_in([a5, b5, c5, d5, e5], nums) or
+
all_in([a1, b2, c3, d4, e5], nums) or
+
all_in([a5, b4, c3, d2, e1], nums)
+
def not_matched(bingo, nums) do
+
Enum.reject(bingo, &(&1 in nums))
+
defp all_in(list, nums) do
+
Enum.all?(list, &(&1 in nums))
+
We simply traverse the `numbers` list aggregating the numbers (order doesn't really matter,
+
here we aggregate them in reverse order to speedup the code). When we have enough numbers
+
that any of the `bingos` is winning one, then we halt the reduction and return computed
+
|> Enum.reduce_while([], fn elem, acc ->
+
case Enum.find(bingos, &Day4.win(&1, matches)) do
+
nil -> {:cont, matches}
+
bingo -> {:halt, Enum.sum(Day4.not_matched(bingo, matches)) * elem}
+
|> Enum.reduce_while({bingos, []}, fn elem, {bingos, acc} ->
+
if Day4.win(bingo, matches) do
+
{:halt, Enum.sum(Day4.not_matched(bingo, matches)) * elem}
+
{:cont, {bingos, matches}}
+
{:cont, {Enum.reject(bingos, &Day4.win(&1, matches)), matches}}