Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us
Notesclub

Day 7: Camel Cards

day-7.livemd

Day 7: Camel Cards

Part one

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, 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, &amp;(&amp;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

Part two

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