-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathday_04.ex
55 lines (47 loc) · 1.64 KB
/
day_04.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
defmodule AdventOfCode.Y2023.Day04 do
@moduledoc """
--- Day 4: Scratchcards ---
Problem Link: https://adventofcode.com/2023/day/4
Difficulty: xs
Tags: set reduction
"""
alias AdventOfCode.Helpers.{InputReader, Transformers}
def input, do: InputReader.read_from_file(2023, 4)
def run(input \\ input()) do
input = parse(input)
card_map = input |> Enum.map(fn {id, _} -> id end) |> Map.new(fn k -> {k, 1} end)
{run_1(input), run_2(input, card_map)}
end
defp run_1(input) do
Enum.reduce(input, 0, fn
{_, one_or_none}, acc when one_or_none < 2 -> acc + one_or_none
{_, matches}, acc -> acc + 2 ** (matches - 1)
end)
end
defp run_2(input, card_map) do
with {end_of_table, _} <- Enum.max_by(input, fn {a, _} -> a end) do
input
|> Enum.reduce(card_map, &updated_cards(&1, end_of_table, &2))
|> Map.values()
|> Enum.sum()
end
end
def parse(data \\ input()) do
for line <- Transformers.lines(data) do
with ["Card", id | cards] <- String.split(line, ~r{\s+}),
{winning, ["|" | got]} <- Enum.split_while(cards, fn v -> v != "|" end),
{id, ":"} <- Integer.parse(id) do
matches = MapSet.intersection(MapSet.new(winning), MapSet.new(got))
{id, MapSet.size(matches)}
end
end
end
defp updated_cards({_, 0}, _, card_map), do: card_map
defp updated_cards({id, count}, end_of_table, card_map) do
Stream.unfold(id + 1, fn n -> {n, n + 1} end)
|> Enum.take(count)
|> Enum.reject(&(&1 > end_of_table))
|> Map.new(fn k -> {k, Map.fetch!(card_map, id)} end)
|> Map.merge(card_map, fn _, v1, v2 -> v1 + v2 end)
end
end