169 lines
3.2 KiB
Elixir
169 lines
3.2 KiB
Elixir
defmodule Solution do
|
|
@spec get_total_winnings(String.t()) :: integer()
|
|
def get_total_winnings(filename, with_jokers \\ false) do
|
|
hands =
|
|
filename
|
|
|> File.stream!()
|
|
|> Enum.map(&parse_line/1)
|
|
|> Map.new()
|
|
|
|
sorted_cards =
|
|
hands
|
|
|> Map.keys()
|
|
|> Enum.sort_by(fn hand -> get_sorting_order(hand, with_jokers) end)
|
|
|
|
sorted_cards
|
|
|> Enum.with_index(1)
|
|
|> Enum.reduce(0, fn {el, idx}, acc -> acc + idx * hands[el] end)
|
|
end
|
|
|
|
defp parse_line(line) do
|
|
[hand, bid] =
|
|
line
|
|
|> String.trim()
|
|
|> String.split(" ")
|
|
|
|
{hand, String.to_integer(bid)}
|
|
end
|
|
|
|
# Map a hand to a list that may be used for sorting.
|
|
defp get_sorting_order(hand, with_jokers) do
|
|
# Map cards to corresponding power,
|
|
# e.g. "57TA" -> [5, 7, 10, 14]
|
|
powers =
|
|
hand
|
|
|> String.graphemes()
|
|
|> Enum.map(fn card -> get_card_power(card, with_jokers) end)
|
|
|
|
# Prepend hand rank.
|
|
[get_rank(hand, with_jokers) | powers]
|
|
end
|
|
|
|
@doc """
|
|
Converts a card symbol to a number.
|
|
|
|
## Examples
|
|
|
|
iex> Solution.get_card_power("J")
|
|
11
|
|
|
|
iex> Solution.get_card_power("J", true)
|
|
1
|
|
|
|
iex> Solution.get_card_power("5")
|
|
5
|
|
"""
|
|
def get_card_power(card, with_jokers \\ false) do
|
|
case card do
|
|
"A" ->
|
|
14
|
|
|
|
"K" ->
|
|
13
|
|
|
|
"Q" ->
|
|
12
|
|
|
|
"J" ->
|
|
if with_jokers, do: 1, else: 11
|
|
|
|
"T" ->
|
|
10
|
|
|
|
num ->
|
|
String.to_integer(num)
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns the rank of a hand based on the number of identical cards.
|
|
|
|
## Examples
|
|
|
|
iex> Solution.get_rank("AAAAA")
|
|
7
|
|
|
|
iex> Solution.get_rank("AA8AA")
|
|
6
|
|
|
|
iex> Solution.get_rank("23332")
|
|
5
|
|
|
|
iex> Solution.get_rank("TTT98")
|
|
4
|
|
|
|
iex> Solution.get_rank("23432")
|
|
3
|
|
|
|
iex> Solution.get_rank("A23A4")
|
|
2
|
|
|
|
iex> Solution.get_rank("23456")
|
|
1
|
|
"""
|
|
def get_rank(hand, with_jokers \\ false) do
|
|
hand = if with_jokers, do: replace_joker(hand), else: hand
|
|
|
|
freq =
|
|
hand
|
|
|> String.graphemes()
|
|
|> Enum.frequencies()
|
|
|> Map.values()
|
|
|> Enum.sort()
|
|
|
|
case freq do
|
|
# five of a kind
|
|
[5] -> 7
|
|
# four of a kind
|
|
[1, 4] -> 6
|
|
# full house
|
|
[2, 3] -> 5
|
|
# three of a kind
|
|
[1, 1, 3] -> 4
|
|
# two pair
|
|
[1, 2, 2] -> 3
|
|
# one pair
|
|
[1, 1, 1, 2] -> 2
|
|
# high card
|
|
_ -> 1
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Replaces all J cards in hand with the card that will result in the best rank.
|
|
|
|
## Examples
|
|
|
|
iex> Solution.replace_joker("T55J5")
|
|
"T5555"
|
|
|
|
iex> Solution.replace_joker("KTJJT")
|
|
"KTTTT"
|
|
|
|
iex> Solution.replace_joker("JJJJJ")
|
|
"AAAAA"
|
|
"""
|
|
def replace_joker(hand) do
|
|
freq =
|
|
hand
|
|
|> String.replace("J", "")
|
|
|> String.graphemes()
|
|
|> Enum.frequencies()
|
|
|
|
if Enum.empty?(Map.keys(freq)) do
|
|
String.replace(hand, "J", "A")
|
|
else
|
|
max_count =
|
|
freq
|
|
|> Map.values()
|
|
|> Enum.max()
|
|
|
|
{most_used_symbol, _} =
|
|
freq
|
|
|> Map.to_list()
|
|
|> Enum.find(fn {_, count} -> count == max_count end)
|
|
|
|
String.replace(hand, "J", most_used_symbol)
|
|
end
|
|
end
|
|
end
|