Add a way to play a round of poker.

This commit is contained in:
Hans Goor 2024-08-18 15:56:13 +00:00
parent 6f721dad3e
commit 6fba8a5435
No known key found for this signature in database

View 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