1
0
Fork 0
advent-of-code/2023/lib/2023/4.ex
2023-12-04 09:09:58 -05:00

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