Clean up code. Add a way to compare scores.
This commit is contained in:
parent
337219ebf3
commit
6f721dad3e
2 changed files with 121 additions and 46 deletions
|
|
@ -1,17 +1,14 @@
|
|||
defmodule PokerEx.Card do
|
||||
@doc ~S"""
|
||||
Holds functions that operate and symbolise a playing card.
|
||||
"""
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
@valid_suits [:spades, :hearts, :diamonds, :clubs]
|
||||
|
||||
@type suit() :: :hearts | :diamonds | :clubs | :spades
|
||||
@type rank() :: integer() | :jack | :queen | :king | :ace
|
||||
@type t() :: %Card{suit: suit(), rank: rank()}
|
||||
|
||||
defstruct [:suit, :rank]
|
||||
@type t() :: %Card{suit: suit(), rank: rank()}
|
||||
defstruct suit: :required,
|
||||
rank: :required
|
||||
|
||||
defguard is_valid_suit(suit) when suit in @valid_suits
|
||||
|
||||
|
|
@ -19,6 +16,17 @@ defmodule PokerEx.Card do
|
|||
when (is_integer(rank) and 2 <= rank and rank <= 10) or
|
||||
rank in [:jack, :queen, :king, :ace]
|
||||
|
||||
@spec rank_to_number(rank()) :: integer()
|
||||
def rank_to_number(rank) do
|
||||
case rank do
|
||||
:jack -> 11
|
||||
:queen -> 12
|
||||
:king -> 13
|
||||
:ace -> 14
|
||||
_ -> rank
|
||||
end
|
||||
end
|
||||
|
||||
@doc ~S"""
|
||||
Checks if a given card is valid. To be valid, it should be the card
|
||||
string with a valid suit and rank, which are specified as module types.
|
||||
|
|
@ -80,19 +88,11 @@ defmodule PokerEx.Card do
|
|||
|
||||
@spec compare(Card.t(), Card.t()) :: :lt | :eq | :gt
|
||||
def compare(first, second) do
|
||||
case [first.rank, second.rank]
|
||||
|> Enum.map(
|
||||
&case &1 do
|
||||
:jack -> 11
|
||||
:queen -> 12
|
||||
:king -> 13
|
||||
:ace -> 14
|
||||
n -> n
|
||||
end
|
||||
) do
|
||||
[f, s] when f < s -> :lt
|
||||
[f, s] when f == s -> :eq
|
||||
[f, s] when f > s -> :gt
|
||||
[f_rank, s_rank] = [first.rank, second.rank] |> Enum.map(&rank_to_number/1)
|
||||
cond do
|
||||
f_rank < s_rank -> :lt
|
||||
f_rank == s_rank -> :eq
|
||||
f_rank > s_rank -> :gt
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
defmodule PokerEx.Combination do
|
||||
alias PokerEx.Card, as: Card
|
||||
import Bitwise
|
||||
alias PokerEx.Card
|
||||
|
||||
@type high_card() :: {:high_card, Card.t()}
|
||||
@type pair() :: {:pair, Card.t()}
|
||||
|
|
@ -24,20 +25,49 @@ defmodule PokerEx.Combination do
|
|||
| straight_flush()
|
||||
| royal_flush()
|
||||
|
||||
@spec means_to_number(score()) :: integer()
|
||||
defp means_to_number({:high_card, %Card{rank: rank}}), do: Card.rank_to_number(rank)
|
||||
|
||||
defp means_to_number({:pair, %Card{rank: rank}}), do: Card.rank_to_number(rank)
|
||||
|
||||
defp means_to_number({:two_pair, {%Card{rank: rank1}, %Card{rank: rank2}}}),
|
||||
do: [rank1, rank2] |> Enum.map(&Card.rank_to_number/1) |> Enum.sum()
|
||||
|
||||
defp means_to_number({:three_of_a_kind, %Card{rank: rank}}), do: Card.rank_to_number(rank)
|
||||
|
||||
defp means_to_number({:straight, {_begin, final}}), do: final
|
||||
|
||||
defp means_to_number({:full_house, {%Card{rank: rank1}, %Card{rank: rank2}}}),
|
||||
do: Card.rank_to_number(rank1) <<< (4 + Card.rank_to_number(rank2))
|
||||
|
||||
defp means_to_number({:four_of_a_kind, %Card{rank: rank}}), do: Card.rank_to_number(rank)
|
||||
|
||||
defp means_to_number({:straight_flush, {_suit, _begin, final}}), do: final
|
||||
|
||||
defp means_to_number(_score), do: 0
|
||||
|
||||
@spec score_to_number(score()) :: integer()
|
||||
defp score_to_number({score, means}) do
|
||||
case score do
|
||||
:high_card -> 0x000
|
||||
:pair -> 0x100
|
||||
:two_pair -> 0x200
|
||||
:three_of_a_kind -> 0x300
|
||||
:straight -> 0x400
|
||||
:flush -> 0x500
|
||||
:full_house -> 0x600
|
||||
:four_of_a_kind -> 0x700
|
||||
:straight_flush -> 0x800
|
||||
:royal_flush -> 0x900
|
||||
end + means_to_number({score, means})
|
||||
end
|
||||
|
||||
@spec straight?(ranks: [Card.rank()]) :: boolean
|
||||
defp straight?(ranks) when length(ranks) < 5, do: false
|
||||
|
||||
defp straight?(ranks) do
|
||||
ranks
|
||||
|> Enum.map(
|
||||
&case &1 do
|
||||
:jack -> 11
|
||||
:queen -> 12
|
||||
:king -> 13
|
||||
:ace -> 14
|
||||
n -> n
|
||||
end
|
||||
)
|
||||
|> Enum.map(&Card.rank_to_number/1)
|
||||
|> Enum.chunk_every(2, 1, :discard)
|
||||
|> Enum.map(
|
||||
&case &1 do
|
||||
|
|
@ -142,6 +172,52 @@ defmodule PokerEx.Combination do
|
|||
end
|
||||
end
|
||||
|
||||
@doc ~S"""
|
||||
Compares two scores and returns their equality.
|
||||
|
||||
When players have the same score, the one with the highest means for
|
||||
this score (i.e., the cards with which the score is obtained) is the winner.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> hand1 = [~p"S3", ~p"C4", ~p"H5", ~p"D6", ~p"C7"]
|
||||
iex> hand2 = [~p"C4", ~p"H5", ~p"D6", ~p"C7", ~p"S8"]
|
||||
iex> [score1, score2] = [hand1, hand2] |> Enum.map(&PokerEx.Combination.evaluate_hand/1)
|
||||
iex> [score1, score2]
|
||||
[{:straight, {3, 7}}, {:straight, {4, 8}}]
|
||||
iex> PokerEx.Combination.compare(score1, score2)
|
||||
:lt
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> hand1 = [~p"S3", ~p"S5", ~p"S6", ~p"S7", ~p"S8"]
|
||||
iex> hand2 = [~p"C4", ~p"H5", ~p"D6", ~p"C7", ~p"S8"]
|
||||
iex> [score1, score2] = [hand1, hand2] |> Enum.map(&PokerEx.Combination.evaluate_hand/1)
|
||||
iex> [score1, score2]
|
||||
[{:flush, :spades}, {:straight, {4, 8}}]
|
||||
iex> PokerEx.Combination.compare(score1, score2)
|
||||
:gt
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> hand1 = [~p"S3", ~p"C4", ~p"H5", ~p"D6", ~p"C7"]
|
||||
iex> hand2 = [~p"S3", ~p"C4", ~p"H5", ~p"D6", ~p"C7"]
|
||||
iex> [score1, score2] = [hand1, hand2] |> Enum.map(&PokerEx.Combination.evaluate_hand/1)
|
||||
iex> [score1, score2]
|
||||
[{:straight, {3, 7}}, {:straight, {3, 7}}]
|
||||
iex> PokerEx.Combination.compare(score1, score2)
|
||||
:eq
|
||||
"""
|
||||
@spec compare(score(), score()) :: :lt | :eq | :gt
|
||||
def compare(score1, score2) do
|
||||
[s1, s2] = [score1, score2] |> Enum.map(&score_to_number/1)
|
||||
|
||||
cond do
|
||||
s1 < s2 -> :lt
|
||||
s1 == s2 -> :eq
|
||||
s1 > s2 -> :gt
|
||||
end
|
||||
end
|
||||
|
||||
@doc ~S"""
|
||||
Finds the highest combination that can be made using the hand and the cards
|
||||
that are present.
|
||||
|
|
@ -155,19 +231,19 @@ defmodule PokerEx.Combination do
|
|||
iex> import PokerEx.Card
|
||||
iex> PokerEx.Combination.evaluate_hand [~p"C10", ~p"CJ", ~p"CQ", ~p"CK", ~p"CA"]
|
||||
{:royal_flush, :clubs}
|
||||
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> PokerEx.Combination.evaluate_hand [~p"CA", ~p"CA", ~p"CA", ~p"CK", ~p"CK"]
|
||||
{:full_house, {%PokerEx.Card{suit: :clubs, rank: :ace}, %PokerEx.Card{suit: :clubs, rank: :king}}}
|
||||
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> PokerEx.Combination.evaluate_hand [~p"CA", ~p"CA", ~p"CA", ~p"D2", ~p"D3"]
|
||||
{:three_of_a_kind, %PokerEx.Card{suit: :clubs, rank: :ace}}
|
||||
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> PokerEx.Combination.evaluate_hand [~p"CA", ~p"CA", ~p"D2", ~p"D3", ~p"D4"]
|
||||
{:pair, %PokerEx.Card{suit: :clubs, rank: :ace}}
|
||||
|
||||
|
||||
iex> import PokerEx.Card
|
||||
iex> PokerEx.Combination.evaluate_hand [~p"CA", ~p"CK", ~p"DJ", ~p"D2", ~p"H7"]
|
||||
{:high_card, %PokerEx.Card{suit: :clubs, rank: :ace}}
|
||||
|
|
@ -177,18 +253,17 @@ defmodule PokerEx.Combination do
|
|||
sorted_hand = hand |> Enum.sort({:asc, Card})
|
||||
freq = hand |> Enum.frequencies()
|
||||
|
||||
[
|
||||
royal_flush(sorted_hand),
|
||||
straight_flush(sorted_hand),
|
||||
four_of_a_kind(freq),
|
||||
full_house(freq),
|
||||
flush(sorted_hand),
|
||||
straight(sorted_hand),
|
||||
three_of_a_kind(freq),
|
||||
two_pair(freq),
|
||||
pair(freq),
|
||||
{:high_card, sorted_hand |> List.last()}
|
||||
]
|
||||
|> Enum.find(&(&1 != nil))
|
||||
cond do
|
||||
rf = royal_flush(sorted_hand) -> rf
|
||||
sf = straight_flush(sorted_hand) -> sf
|
||||
fok = four_of_a_kind(freq) -> fok
|
||||
fh = full_house(freq) -> fh
|
||||
fl = flush(sorted_hand) -> fl
|
||||
st = straight(sorted_hand) -> st
|
||||
tok = three_of_a_kind(freq) -> tok
|
||||
tp = two_pair(freq) -> tp
|
||||
p = pair(freq) -> p
|
||||
true -> {:high_card, sorted_hand |> List.last()}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue