sample_input =
"""
Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
"""
defmodule Scratchcards do
def count_points(input) do
input
|> number_of_matches_per_card()
|> Enum.map(fn
0 -> 0
number_of_matches -> Integer.pow(2, number_of_matches - 1)
end)
|> Enum.sum()
end
def count_scratchcards(input) do
input
|> number_of_matches_per_card()
|> Enum.with_index(1)
|> Enum.reduce(%{}, fn
{matches, index}, acc ->
acc = Map.update(acc, index, 1, &(&1 + 1))
if matches == 0 do
acc
else
amount = Map.get(acc, index, 0)
(index + 1)..(index + matches)
|> Enum.reduce(acc, fn card_nr, acc ->
Map.update(acc, card_nr, amount, &(&1 + amount))
end)
end
end)
|> Map.values()
|> Enum.sum()
end
defp number_of_matches_per_card(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
[_, winning_numbers, own_numbers] = Regex.split(~r/:|\|/, line)
winning_numbers = string_to_list_of_numbers(winning_numbers)
own_numbers = string_to_list_of_numbers(own_numbers)
MapSet.intersection(winning_numbers, own_numbers) |> Enum.count()
end)
end
defp string_to_list_of_numbers(string) do
string |> String.split(" ", trim: true) |> Enum.map(&String.to_integer/1) |> MapSet.new()
end
end
Scratchcards.count_points(sample_input)
# expect 13
Path.join(__DIR__, "day-4.input")
|> File.read!()
|> Scratchcards.count_points()
# 20829
Scratchcards.count_scratchcards(sample_input)
# 30
Path.join(__DIR__, "day-4.input")
|> File.read!()
|> Scratchcards.count_scratchcards()
# 12648035