57 lines
1.4 KiB
Elixir
57 lines
1.4 KiB
Elixir
defmodule Card do
|
|
defp split(str) do
|
|
str
|
|
|> String.trim()
|
|
|> String.split(" ")
|
|
|> Enum.filter(fn s -> String.length(s) !== 0 end)
|
|
end
|
|
|
|
defp count_winning_cards(player_card, winning_numbers) do
|
|
player_card |> Enum.filter(fn n -> Enum.any?(winning_numbers, &(&1 == n)) end) |> Enum.count()
|
|
end
|
|
|
|
defp parse_card("Card " <> rest) do
|
|
[_, numbers] = rest |> String.split(":")
|
|
[winning, player] = numbers |> String.split("|")
|
|
|
|
[winning |> split(), player |> split()]
|
|
end
|
|
|
|
def parse(input) do
|
|
for card <- input |> String.split("\n"),
|
|
card != "",
|
|
[winning_numbers, our_numbers] = parse_card(card) do
|
|
[winning_numbers, our_numbers]
|
|
end
|
|
end
|
|
|
|
def part1(cards) do
|
|
for [winning_numbers, our_numbers] <- cards do
|
|
case count_winning_cards(our_numbers, winning_numbers) do
|
|
n when n > 0 -> 2 ** (n - 1)
|
|
0 -> 0
|
|
end
|
|
end
|
|
|> Enum.sum()
|
|
end
|
|
|
|
def part2(cards) do
|
|
cards
|
|
|> Enum.with_index()
|
|
|> Enum.reduce(
|
|
List.duplicate(1, cards |> Enum.count()),
|
|
fn {[winning, player], idx}, copies ->
|
|
self_copies = Enum.at(copies, idx)
|
|
won = count_winning_cards(player, winning)
|
|
slice = if won > 0, do: (idx + 1)..(idx + won), else: (..)
|
|
|
|
copies
|
|
|> Enum.with_index()
|
|
|> Enum.map(fn {count, idx} ->
|
|
if idx in slice, do: count + self_copies, else: count
|
|
end)
|
|
end
|
|
)
|
|
|> Enum.sum()
|
|
end
|
|
end
|