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