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

--- Day 7: Camel Cards ---

2023/day_7.livemd

— Day 7: Camel Cards —

Mix.install([{:kino, "~> 0.11.3"}])

Part One

test_input = Kino.Input.textarea("test_input")
cards_input = Kino.Input.textarea("cards_input")
defmodule CamelCards do
  def deck("T"), do: 10
  def deck("J"), do: 11
  def deck("Q"), do: 12
  def deck("K"), do: 13
  def deck("A"), do: 14
  def deck(card), do: String.to_integer(card)

  def deck2("J"), do: 1
  def deck2(card), do: deck(card)

  def parse(input) do
    input
    |> Kino.Input.read()
    |> String.split("\n")
    |> Enum.map(&String.split(&1, " "))
    |> Enum.map(fn [cards, bid] -> {cards, String.to_integer(bid)} end)
  end

  def part_one(input) do
    input
    |> parse()
    |> Enum.map(fn {cards, bid} ->
      {cards
       |> String.graphemes()
       |> Enum.map(&deck/1), bid}
    end)
    |> Enum.map(&hand_type/1)
    |> Enum.sort_by(fn {score, cards, _bid} -> [score | cards] end)
    |> Enum.with_index(1)
    |> Enum.reduce(0, fn {{_rank, _cards, bid}, i}, acc -> acc + bid * i end)
  end

  def part_two(input) do
    input
    |> parse()
    |> Enum.map(fn {cards, bid} ->
      {cards
       |> String.graphemes()
       |> Enum.map(&deck2/1), bid}
    end)
    |> Enum.map(&hand_type/1)
    |> Enum.sort_by(fn {score, cards, _bid} -> [score | cards] end)
    |> Enum.with_index(1)
    |> Enum.reduce(0, fn {{_rank, _cards, bid}, i}, acc -> acc + bid * i end)
  end

  def hand_type({cards, bid}) do
    non_jokers = Enum.filter(cards, &(&1 > 1))
    non_jokers = if length(non_jokers) == 0, do: cards, else: non_jokers

    score =
      non_jokers
      |> Enum.frequencies()
      |> Map.values()
      |> Enum.sort(:desc)
      |> then(fn [top | rest] -> [top + (5 - length(non_jokers)) | rest] end)
      |> score_hand()

    {score, cards, bid}
  end

  def score_hand([5 | _rest]), do: 7
  def score_hand([4 | _rest]), do: 6
  def score_hand([3, 2 | _rest]), do: 5
  def score_hand([3 | _rest]), do: 4
  def score_hand([2, 2 | _rest]), do: 3
  def score_hand([2 | _rest]), do: 2
  def score_hand(_), do: 1
end
CamelCards.part_one(cards_input)
CamelCards.part_two(cards_input)