Skip to content

Instantly share code, notes, and snippets.

@arosenb2
Created December 5, 2023 04:09
Show Gist options
  • Save arosenb2/ff6ea72a48ae9c23e34c7a7808d5d3c1 to your computer and use it in GitHub Desktop.
Save arosenb2/ff6ea72a48ae9c23e34c7a7808d5d3c1 to your computer and use it in GitHub Desktop.
AoC - Day 4
defmodule AdventOfCode.Day4.Part1 do
def process_input(input) do
input
|> String.trim()
|> String.split("\n")
end
def process(cards) do
cards
|> Enum.map(&process_card/1)
|> Enum.map(&calculate_winners/1)
|> Enum.map(&calculate_score/1)
end
def process_card(card) do
["Card " <> id, values] = String.split(card, ": ", trim: true)
[winning_numbers, my_numbers] = String.split(values, " | ", trim: true)
winning_numbers =
String.split(winning_numbers, ~r/\D+/, trim: true)
|> Enum.map(&String.to_integer/1)
my_numbers =
String.split(my_numbers, ~r/\D+/, trim: true)
|> Enum.map(&String.to_integer/1)
{id, winning_numbers, my_numbers}
end
def calculate_winners({id, winning_numbers, my_numbers}) do
winners =
Enum.frequencies(winning_numbers ++ my_numbers)
|> Map.filter(fn {_key, value} -> value > 1 end)
|> Map.keys()
{id, winners}
end
def calculate_score({_id, []}), do: 0
def calculate_score({_id, winners}) do
Integer.pow(2, length(winners) - 1)
end
end
defmodule AdventOfCode.Day4.Part2 do
def format_id(id) do
id
|> String.trim()
|> String.to_integer()
end
def process(cards) do
total_cards = length(cards)
processed_cards =
cards
|> Enum.map(fn card ->
{id, winners, my_numbers} = AdventOfCode.Day4.Part1.process_card(card)
{format_id(id), winners, my_numbers}
end)
copies =
processed_cards
|> Enum.map(fn {id, _, _} -> {id, 0} end)
|> Enum.into(%{})
Enum.reduce(processed_cards, copies, fn card, acc ->
{id, winners, my_numbers} = card
{id, winners} = AdventOfCode.Day4.Part1.calculate_winners({id, winners, my_numbers})
case length(winners) do
0 ->
acc
num_of_winners ->
additional_copies = Map.get(acc, id)
ids_to_increment =
(id + 1)..min(id + num_of_winners, total_cards)
|> Range.to_list()
|> List.duplicate(additional_copies + 1)
|> List.flatten()
increment_winning_copies(acc, ids_to_increment)
end
end)
|> Enum.map(fn {key, value} -> {key, value + 1} end)
|> Map.new()
end
def increment_winning_copies(copies_map, []), do: copies_map
def increment_winning_copies(copies_map, [id | remaining_ids]) do
Map.update(copies_map, id, 1, fn previous -> previous + 1 end)
|> increment_winning_copies(remaining_ids)
end
end
defmodule AdventOfCode.Day4 do
@moduledoc """
This was originally done in Livebook,
and I used the Kino.AoC Smart Cell to
retrieve the input data.
"""
def solve_part1(input) do
input
|> AdventOfCode.Day4.Part1.process_input()
|> AdventOfCode.Day4.Part1.process()
|> Enum.sum()
```
end
def solve_part2(input) do
input
|> AdventOfCode.Day4.Part1.process_input()
|> AdventOfCode.Day4.Part2.process()
|> Map.values()
|> Enum.sum()
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment