Add a way to play a round of poker.
This commit is contained in:
parent
6f721dad3e
commit
6fba8a5435
1 changed files with 92 additions and 0 deletions
92
poker_ex/lib/poker_ex/round.ex
Normal file
92
poker_ex/lib/poker_ex/round.ex
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
defmodule PokerEx.Round do
|
||||
alias __MODULE__
|
||||
alias PokerEx.Card
|
||||
alias PokerEx.Deck
|
||||
alias PokerEx.Combination
|
||||
|
||||
@type player_state() :: :folded | :all_in | :active
|
||||
@type player() :: %{name: String.t(), state: player_state(), hand: {Card.t(), Card.t()}}
|
||||
@type stage() :: :pre_flop | :flop | :turn | :river
|
||||
@type round_result() ::
|
||||
{:end, Round.t(), [player()]} | {:next, Round.t()} | {:error, String.t()}
|
||||
@type player_action() :: {:raise, integer()} | {:call} | {:fold}
|
||||
|
||||
@type t() :: %Round{
|
||||
pot: integer(),
|
||||
stage: stage(),
|
||||
deck: Deck.deck(),
|
||||
cards: [Card.t()],
|
||||
players: [player()],
|
||||
player_at_turn: integer(),
|
||||
last_better: integer(),
|
||||
dealer: integer()
|
||||
}
|
||||
@enforce_keys [:players, :dealer]
|
||||
defstruct pot: 0,
|
||||
stage: :pre_flop,
|
||||
deck: Deck.new_shuffled(),
|
||||
cards: [],
|
||||
players: [],
|
||||
player_at_turn: 0,
|
||||
last_better: 0,
|
||||
dealer: 0
|
||||
|
||||
@spec evaluate_player({Card.t(), Card.t()}, [Card.t()]) ::
|
||||
{Combination.score(), {integer(), integer()}}
|
||||
defp evaluate_player({card1, card2}, round_cards) do
|
||||
[card1, card2] = Enum.sort([card1, card2], Card)
|
||||
|
||||
{
|
||||
([card1, card2] ++ round_cards) |> Combination.evaluate_hand(),
|
||||
{Card.rank_to_number(card1.rank), Card.rank_to_number(card2.rank)}
|
||||
}
|
||||
end
|
||||
|
||||
@spec take_while_max_by([any()], (Enum.element() -> any())) :: [any()]
|
||||
defp take_while_max_by(sorted_list, fun) do
|
||||
case sorted_list do
|
||||
[] ->
|
||||
[]
|
||||
|
||||
[head | _] ->
|
||||
highest = fun.(head)
|
||||
Enum.take_while(sorted_list, &(fun.(&1) == highest))
|
||||
end
|
||||
end
|
||||
|
||||
@spec winners(Round.t()) :: {[player()], Combination.score()}
|
||||
defp winners(round) do
|
||||
winning_players =
|
||||
round.players
|
||||
|> Enum.filter(&(&1.state != :folded))
|
||||
|> Enum.map(&{&1, evaluate_player(&1.hand, round.cards)})
|
||||
|> Enum.sort_by(fn {_player, {score, _hand}} -> score end, {:desc, Combination})
|
||||
|> take_while_max_by(fn {_player, {score, _hand}} -> score end)
|
||||
|> Enum.sort_by(fn {_player, {_score, hand}} -> hand end, :desc)
|
||||
|> take_while_max_by(fn {_player, {_score, hand}} -> hand end)
|
||||
|
||||
case winning_players do
|
||||
[] ->
|
||||
[]
|
||||
|
||||
[winner | tail] ->
|
||||
{_, {winning_score, _}} = winner
|
||||
{[winner | tail] |> Enum.map(fn {player, _score} -> player end), winning_score}
|
||||
end
|
||||
end
|
||||
|
||||
@spec play(Round.t(), player_action()) :: round_result()
|
||||
def play(round, {:fold}) do
|
||||
{
|
||||
:next,
|
||||
%{
|
||||
round
|
||||
| players: List.update_at(round.players, round.player_at_turn, &%{&1 | state: :folded}),
|
||||
player_at_turn: rem(round.player_at_turn + 1, length(round.players))
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def play(round, current_player_action) do
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue