sample_input =
"""
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
"""
defmodule CamelCards do
def total_winnings(hands, mode \\ :jokers_are_not_special)
when mode in [:jokers_are_special, :jokers_are_not_special] do
hands
|> String.split("\n", trim: true)
|> Enum.map(fn <<hand::binary-5, " ", bid::binary>> ->
{hand, String.to_integer(bid)}
end)
|> Enum.sort_by(
fn {hand, _} -> {collatable_type(hand, mode), collatable_strength(hand, mode)} end,
:desc
)
|> Enum.with_index(1)
|> Enum.reduce(0, fn {{_hand, bid}, rank}, acc -> acc + bid * rank end)
end
@type_collation_mapping ~w(five_of_a_kind four_of_a_kind full_house three_of_a_kind two_pair one_pair high_card)a
|> Enum.with_index()
defp collatable_type(hand, mode) do
hand = to_charlist(hand)
{maybe_jokers, rest_of_hand} =
case mode do
:jokers_are_special -> Enum.split_with(hand, &(&1 == ?J))
_ -> {[], hand}
end
type =
rest_of_hand
|> Enum.frequencies()
|> Map.values()
|> Enum.sort(:desc)
|> then(fn
[first | rest] ->
[first + length(maybe_jokers) | rest]
[] ->
[length(maybe_jokers)]
end)
|> case do
[5] -> :five_of_a_kind
[4, 1] -> :four_of_a_kind
[3, 2] -> :full_house
[3, 1, 1] -> :three_of_a_kind
[2, 2, 1] -> :two_pair
[2, 1, 1, 1] -> :one_pair
[1, 1, 1, 1, 1] -> :high_card
end
@type_collation_mapping[type]
end
@strength_collation_mapping ~c(AKQJT98765432) |> Enum.with_index() |> Enum.into(%{})
@strength_collation_mapping_jokers_are_special ~c(AKQT98765432J)
|> Enum.with_index()
|> Enum.into(%{})
defp collatable_strength(hand, mode) do
hand
|> to_charlist()
|> Enum.map(fn c ->
case mode do
:jokers_are_special -> @strength_collation_mapping_jokers_are_special[c]
_ -> @strength_collation_mapping[c]
end
end)
end
end
CamelCards.total_winnings(sample_input)
# expected: 6440
Path.join(__DIR__, "day-7.input")
|> File.read!()
|> CamelCards.total_winnings()
# 251106089
CamelCards.total_winnings(sample_input, :jokers_are_special)
# expected: 5905
Path.join(__DIR__, "day-7.input")
|> File.read!()
|> CamelCards.total_winnings(:jokers_are_special)
# 249620106