91 lines
1.9 KiB
Elixir
91 lines
1.9 KiB
Elixir
import AOC
|
|
|
|
aoc 2023, 4 do
|
|
def p1(input) do
|
|
input
|
|
|> String.split("\n")
|
|
|> Stream.map(&parse_line/1)
|
|
|> Stream.map(&score_1/1)
|
|
|> Enum.sum()
|
|
end
|
|
|
|
def p2(input) do
|
|
cards =
|
|
input
|
|
|> String.split("\n")
|
|
|> Enum.map(&parse_line/1)
|
|
|> Enum.map(&score_2/1)
|
|
|
|
card_counts =
|
|
cards
|
|
|> Stream.map(fn {id, _} -> {id, 1} end)
|
|
|> Enum.into(%{})
|
|
|
|
cards
|
|
|> Enum.reduce(card_counts, fn {id, winners}, counts ->
|
|
if winners > 0 do
|
|
copies = Map.get(counts, id)
|
|
|
|
copied_range =
|
|
(id + 1)..(id + winners)
|
|
|
|
for copy_id <- copied_range, reduce: counts do
|
|
counts ->
|
|
if Map.has_key?(counts, copy_id) do
|
|
Map.update!(counts, copy_id, &(&1 + copies))
|
|
else
|
|
counts
|
|
end
|
|
end
|
|
else
|
|
counts
|
|
end
|
|
end)
|
|
|> Map.values()
|
|
|> Enum.sum()
|
|
end
|
|
|
|
def parse_line(line) do
|
|
["Card " <> card_string, numbers_string] = String.split(line, ": ")
|
|
[winning_string, you_have_string] = String.split(numbers_string, " | ")
|
|
|
|
card =
|
|
card_string
|
|
|> String.trim()
|
|
|> String.to_integer()
|
|
|
|
winning =
|
|
winning_string
|
|
|> String.split(" ", trim: true)
|
|
|> Enum.map(&String.to_integer/1)
|
|
|
|
you_have =
|
|
you_have_string
|
|
|> String.split(" ", trim: true)
|
|
|> Enum.map(&String.to_integer/1)
|
|
|
|
{card, winning, you_have}
|
|
end
|
|
|
|
def score_1({_, winning, you_have}) do
|
|
number_of_winners =
|
|
winning
|
|
|> Enum.filter(&Enum.member?(you_have, &1))
|
|
|> Enum.count()
|
|
|
|
if number_of_winners < 1 do
|
|
0
|
|
else
|
|
2 ** (number_of_winners - 1)
|
|
end
|
|
end
|
|
|
|
def score_2({id, winning, you_have}) do
|
|
number_of_winners =
|
|
winning
|
|
|> Enum.filter(&Enum.member?(you_have, &1))
|
|
|> Enum.count()
|
|
|
|
{id, number_of_winners}
|
|
end
|
|
end
|